Are array views possible? - javascript

I would like to know if it's possible to mimic the constrained boundaries behaviour of an ArrayBufferView over an ArrayBuffer in a cross-browser compatible way (down to say IE8).
Consider a Javascript array structure like this:
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
I would like to obtain an array view b of a subset of a. Such as when an index of b is mutated, so is an index in a.
Usage example:
var b = ViewOf(a, 3, 6); // Make a view of a, from index 3 to 6
console.log(b); // [3, 4, 5, 6]
b[0] = 42;
console.log(a); // [0, 1, 2, 42, 4, 5, 6, 7, 8, 9]

i don't know about IE8, since it's Object.defineProperty is janky, but this seems to do what you ask, even if what you ask isn't the best idea ever for reasons pointed out in other comments:
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function ViewOf(orig, from, to){
var sub=orig.slice(from, to);
for(var i=0, mx=sub.length;i<mx;i++){(function(i){ var it=sub[i];
Object.defineProperty(sub, i, { get: function(){ return it;}, set: function(v){ return it=orig[i+from]=v; } });
}(i));}
return sub;
}
var b = ViewOf(a, 3, 6); // Make a view of a, from index 3 to 6
console.log(b); // [3, 4, 5, 6]
b[0] = 42;
console.log(a); //shows: [0, 1, 2, 42, 4, 5, 6, 7, 8, 9]

That's not possible by default. you can mimic it with a custom function.
var a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
ViewOf = function(a, startIdxx, endIdxx){
return {
startIdx: startIdxx,
endIdx: endIdxx,
set: function(index, value){
a[index+this.startIdx] = value;
},
get: function(index){
return a[index+this.startIdx];
}
}
}
Now you can use the above function like below
b = ViewOf(a, 3, 6);
b.set(0, 42);
console.log(a);
JS Fiddle: http://jsfiddle.net/YewC4/4/

Have a look at https://github.com/inexorabletash/polyfill.
This polyfill lib has typedarray.js which contains polyfills for ArrayBuffer and ArrayBufferView.
I do not know this lib. Only a quick googleing..

Related

Delete all elements from an array A which are present in an array B without using a double loop

So, as an input I have two arrays, A and B. Let's suppose that these are the values inside the two:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and B = [1, 3, 5, 7, 9]
After the deletion the array A should be [2, 4, 6, 8, 10].
I have written (Javascript) this functioning algorithm to solve this problem:
for (var i=0; i < A.length; i++) {
for (var j=0; j < B.length; j++) {
if(B[j] == A[i])
A.splice(i, 1) // Removes 1 element of the array starting from position i
}
}
I would like to know, is it possible to solve this problem without using a double loop?
What about this:
let A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ;
const B = [1, 3, 5, 7, 9];
A = A.filter(num => !B.includes(num));
Yes it is. You could use a Set. In terms of Set operations you are computing the difference A \ B.
Using a set which is optimized for lookups in O(1) time will speed up the computing the difference siginificantly from O(n²) when using includes() or double for loop to O(n).
const A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const B = [1, 3, 5, 7, 9]
const setB = new Set(B);
const difference = A.filter(x => !setB.has(x));
console.log(difference);
Maybe that ?
const
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
, B = [1, 2, 3, 5, 7, 9] // no gaps in 1,2 and 2,3
;
for (let i =0, j=0 ; i < A.length; i++)
{
if (A[i]===B[j]) { A.splice(i--,1); j++ }
}
document.write( JSON.stringify(A) )
or (faster code)
const
A = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
, B = [ 1, 3, 5, 7, 9 ]
;
for (let i = A.length, j= B.length -1 ; i-- ; )
{
if (A[i]===B[j]) { A.splice(i,1); j-- }
}
document.write( JSON.stringify(A) )

Adding library function for sorting array gives undefined

I am trying to add a Library function for sorting Items in an array. Though I got link and way, but when trying to make a library function, this doesn't work. can someone help me out as it is responding undefined as result.
var arr1 = [5, 4, 2, 6, 9, 2, 8, 1, 6];
Array.prototype.sortItems = function(){
this.sort((a,b) => a - b);
}
console.log(arr1.sortItems());
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
you need to return the result of this.sort()
var arr1 = [5, 4, 2, 6, 9, 2, 8, 1, 6];
Array.prototype.sortItems = function(){
return this.sort((a,b) => a - b);
}
console.log(arr1.sortItems());
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try returning the result
var arr1 = [5, 4, 2, 6, 9, 2, 8, 1, 6];
Array.prototype.sortItems = function(){
return this.sort((a,b) => a - b);
}
console.log(arr1.sortItems());
FYI, compareFunction is optional
var arr1 = [5, 4, 2, 6, 9, 2, 8, 1, 6];
console.log(arr1.sort());

Check if the sub set of numbers is in starting part of the series or bottom part of the series using jQuery or javascript

For example: I have set 1,3,4,5,6,7,8,10,11
scenario 1 : subset = 1,3,4 which is in starting part of the series = Acceptable
scenario 2 : subset = 8,10,11 which is in ending part of the series = Acceptable
scenario 3 : subset = 1,3,10,11 which is in both starting and ending part of the series = Acceptable
scenario 4 : subset = 1,3,6,8 which is in starting part of series and also in the middle of the series = Not Acceptable.
Main thing to achieve is to check if the given series is in starting part of the series or ending part without breaking the series using jquery or javacript
Help will be much appreciated
Thanks in advance
You could use a two pass approach, with first collecting for all subarray items the comparison at the same index from start and end (later denoted as left and right side).
To indicate a result, 4 states are returned which mean
0 - no match, neither from the left nor from the right side matches the value,
1 - item of the left side of the array matches,
2 - item of the right side of the array matches,
3 - item matches on both sides.
After collecting the values which represent match and position, the values have to be consolidated to the wanted result, true or false.
To check each value, you need another value which represents the expected side. At start, the expected side is set to 1, because it starts at the left side to check.
The temporary result of the callback with Array#every is a single check if the actual value is greater or equal to the expected value. This includes indicator 3 because this value is in both sides. A value of zero exits the loop as well.
If a value of 2 is found, then it indicates the right side and all following elements have to be greater than 2, therefor the expected value is set to 2.
The presented solution could be shortened to just return the wanted boolean value.
function check(array, subarray) {
var expected = 1,
temp = subarray.map(function (a, i) {
var offset = array.length - subarray.length;
return (a === array[i]) + 2 * (a === array[i + offset]);
}),
result = temp.every(function (a) {
var r = a >= expected;
if (a === 2) {
expected = 2;
}
return r;
});
return temp.concat(result);
}
var array = [1, 3, 4, 5, 6, 7, 8, 10, 11];
console.log(check(array, [1, 3, 4])); // true
console.log(check(array, [8, 10, 11])); // true
console.log(check(array, [1, 3, 10, 11])); // true
console.log(check(array, [1, 3, 6, 8])); // false
console.log(check([1, 2, 3, 4, 5, 6], [1, 4, 3, 6])); // false
console.log(check([1, 2, 3, 4, 5, 6], [1, 4, 3, 6])); // false
console.log(check([1, 2, 3, 2, 3, 4], [3, 2, 3, 2])); // false
console.log(check([1, 2, 3, 2, 3, 4], [1, 2, 3, 4])); // true
.as-console-wrapper { max-height: 100% !important; top: 0; }
The short version without a temporary array.
function check(array, subarray) {
var offset = array.length - subarray.length,
expected = 1;
return subarray.every(function (a, i) {
var state = (a === array[i]) + 2 * (a === array[i + offset]),
result = state >= expected;
if (state === 2) {
expected = 2;
}
return result;
});
}
var array = [1, 3, 4, 5, 6, 7, 8, 10, 11];
console.log(check(array, [1, 3, 4])); // true
console.log(check(array, [8, 10, 11])); // true
console.log(check(array, [1, 3, 10, 11])); // true
console.log(check(array, [1, 3, 6, 8])); // false
console.log(check([1, 2, 3, 4, 5, 6], [1, 4, 3, 6])); // false
console.log(check([1, 2, 3, 4, 5, 6], [1, 4, 3, 6])); // false
console.log(check([1, 2, 3, 2, 3, 4], [3, 2, 3, 2])); // false
console.log(check([1, 2, 3, 2, 3, 4], [1, 2, 3, 4])); // true
.as-console-wrapper { max-height: 100% !important; top: 0; }
You would iterate through the subarray from left to right, and from right to left, and stop where the value does not match with the value in the main array at the "corresponding position", i.e. the position counting from the same side of the array.
If at the end of both loops all values of the subarray matched, i.e. the two indexes crossed each other, then the result is true.
Here is the code:
function isSubsetAtEnds(array, subarray) {
const diff = array.length - subarray.length;
let i, j;
if (diff < 0) return false;
for (i = 0; i < subarray.length; i++)
if (array[i] !== subarray[i]) break;
for (j = subarray.length - 1; j >= i; j--)
if (array[j+diff] !== subarray[j]) break;
return j < i;
}
var array = [1, 3, 4, 5, 6, 7, 8, 10, 11];
console.log(isSubsetAtEnds(array, [1, 3, 4])); // true
console.log(isSubsetAtEnds(array, [8, 10, 11])); // true
console.log(isSubsetAtEnds(array, [1, 3, 10, 11])); // true
console.log(isSubsetAtEnds(array, [1, 3, 6, 8])); // false
One simple approach: remove matching numbers from the beginning and end of both arrays, and see if there are any leftovers.
var checkIt = function(arr,subarr) {
// strip off matching numbers at the beginning
while (subarr.length && arr[0] === subarr[0]) {
arr.shift();
subarr.shift();
}
// strip off matching numbers at the end
while (subarr.length && arr[arr.length - 1] === subarr[subarr.length - 1]) {
arr.pop();
subarr.pop();
}
// if there aren't any leftovers, return true
return (subarr.length === 0)
}
console.log(checkIt( [1, 3, 4, 5, 6, 7, 8, 10, 11],[1, 3, 4]));
console.log(checkIt( [1, 3, 4, 5, 6, 7, 8, 10, 11],[8, 10, 11]));
console.log(checkIt( [1, 3, 4, 5, 6, 7, 8, 10, 11],[1, 3, 10, 11]));
console.log(checkIt( [1, 3, 4, 5, 6, 7, 8, 10, 11],[1, 3, 6, 8]));
// pathological edge case:
console.log(checkIt( [1,2,3,2,1],[1,2,3,2,1] ))
// This returns true, but based on the rules of the puzzle I'm honestly not sure whether that's correct.

Is JavaScript's array map prototype a little off?

I was playing around with JavaScript's array prototype map and I don't understand why I'm getting the following values:
console.log(
[1,2,2,5,6].map(function(a,b){
return a+b;
})
); /*This returns [ 1, 3, 4, 8, 10 ]*/
Shouldn't the above code return [1,3,4,7,11] ?
Here's another snippet which shows that elements in the array are added sequentially and are correct at least I believe so.
console.log(
[1,2,3,4,5,6].map(function(a,b){
return a+b;
})
); /*[ 1, 3, 5, 7, 9, 11 ]*/
This is just a curious question more along the lines of why the first snippet of code seems.
It's because map passes you the value as the first parameter and the index as the second. So, what you're adding is: 1 + 0, 2+1, 2+2, 5+3, etc.
Your a value is the value out of the array: 1, 2, 2, 5, 6
Your b value is actually an index, not a value out of the array: 0, 1, 2, 3, 4
Let's sum:
[1, 2, 2, 5, 6] // Your values
+ [0, 1, 2, 3, 4] // Indices
-----------------
[1, 3, 4, 8,10] // Result
[1, 2, 3, 4, 5, 6] // Your values
+ [0, 1, 2, 3, 4, 5] // Indices
--------------------
[1, 3, 5, 7, 9,11] // Result
The results are correct.
I think you are confusing map with reduce:
var arr = [];
[1,2,2,5,6].reduce(function(a,b){
arr.push(a+b);
return b;
}, 0);
arr; // [1, 3, 4, 7, 11]
[0, 1, 2, 2, 5] // Values returned in previous iteration
+ [1, 2, 2, 5, 6] // Your values
-----------------
[1, 3, 4, 7,11] // Result
so the first parameter 'a' is value and the 'b' is index. so adding together it shows the corect value only. so 'a' contains [1, 2, 2, 5, 6] and 'b' contains [0, 1, 2, 3, 4]

How can I change the position of a particular item in an array?

I'm trying to change an item's index position in an array, but I cannot figure out a way.
{
"items": [
1,
3,
2
]
}
You can use splice to move an element in an array:
var arr = [
1,
3,
2
];
var oldIndex = 2,
newIndex = 1;
arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);
This makes [1, 2, 3]
The internal splice removes and returns the element, while the external one inserts it back.
Just for fun I defined a generic function able to move a slice, not just an element, and doing the computation of the index:
Object.defineProperty(Array.prototype, "move", {
value:function(oldIndex, newIndex, nbElements){
this.splice.apply(
this, [newIndex-nbElements*(newIndex>oldIndex), 0].concat(this.splice(oldIndex, nbElements))
);
}
});
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(5, 3, 4);
console.log('1:', arr) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 7, 8, 3, 4, 5, 6, 9];
arr.move(3, 9, 2);
console.log('2:', arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var arr = [0, 1, 2, 4, 5, 3, 6, 7];
arr.move(5, 3, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
var arr = [0, 3, 1, 2, 4, 5, 6, 7];
arr.move(1, 4, 1);
console.log('3:', arr); // [0, 1, 2, 3, 4, 5, 6, 7]
JS Bin
If you want to sort them in Unicode order (where numbers become strings) you can use sort() function.
items.sort();
If you have your custom order, you need to provide a sort function to the sort function.
function compare(a, b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
// a must be equal to b
return 0;
}
and you use it like this:
items.sort(compare(a, b));

Categories