Related
I have an n-dimensional array and I want to access/modify an element in it using another array to specify the indices.
I figured out how to access a value, however I do not know how to modify the original value.
// Arbitrary values and shape
arr = [[[8, 5, 8],
[9, 9, 9],
[0, 0, 1]],
[[7, 8, 2],
[9, 8, 3],
[9, 5, 6]]];
// Arbitrary values and length
index = [1, 2, 0];
// The following finds the value of arr[1][2][0]
// Where [1][2][0] is specified by the array "index"
tmp=arr.concat();
for(i = 0; i < index.length - 1; i++){
tmp = tmp[index[i]];
}
// The correct result of 9 is returned
result = tmp[index[index.length - 1]];
How can I modify a value in the array?
Is there a better/more efficient way to access a value?
This is a classic recursive algorithm, as each step includes the same algorithm:
Pop the first index from indices.
Keep going with the array that the newly-popped index points to.
Until you get to the last element in indices - then replace the relevant element in the lowest-level array.
function getUpdatedArray(inputArray, indices, valueToReplace) {
const ans = [...inputArray];
const nextIndices = [...indices];
const currIndex = nextIndices.shift();
let newValue = valueToReplace;
if (nextIndices.length > 0) {
newValue = getUpdatedArray(
inputArray[currIndex],
nextIndices,
valueToReplace,
);
} else if (Array.isArray(inputArray[currIndex])) {
throw new Error('Indices array points an array');
}
ans.splice(currIndex, 1, newValue);
return ans;
}
const arr = [
[
[8, 5, 8],
[9, 9, 9],
[0, 0, 1]
],
[
[7, 8, 2],
[9, 8, 3],
[9, 5, 6]
]
];
const indices = [1, 2, 0];
const newArr = getUpdatedArray(arr, indices, 100)
console.log(newArr);
You can change the values in array like this,
arr[x][y][z] = value;
Does this help?
I think what you're looking for is this:
arr[index[0]][index[1]][index[2]] = value;
I'm having trouble understanding what you're attempting to do in the second part of your example.
Given the following array
let array = [[1, 2], [1, 2], [3, 4], [5, 6], [2, 1]]
I want to return the number of distinct arrays in this set. So the example above should return 3. How do I achieve this? I tried the code below, but it does not give the right answer
let distinct = 0
for (let i = 0; i < array.length; i++) {
for (let j = i + 1; j < array.length - i; j++) {
let difference = ingredients[i].filter(x => !array[j].includes(x))
if (difference.length > 0) {
distinct += 1;
}
}
}
return distinct;
If the order inside a sub item matters
Use Array.map() to convert each sub-array into a string (I've used String() as suggested by #trincot), create a Set from the array to remove duplicates, and get the size of the Set:
const array = [[1, 2], [1, 2], [3, 4], [5, 6]]
const distinct = new Set(array.map(String))
console.log(distinct.size)
If the order doesn't matter
Sort each sub item, and then convert to string:
const array = [[2, 1], [1, 2], [3, 4], [5, 6]]
const distinct = new Set(array.map(o => String(o.sort())))
console.log(distinct.size)
I didn't check your algorithm at all, just corrected your syntax. Is this what you meant to write?:
let array = [
[1, 2],[1, 2],[3, 4],[5, 6]
];
console.log(countDistinctArrays(array));
function countDistinctArrays(parentArray) {
let distinct = 0;
for (let i = 0; i < parentArray.length; i++) {
for (let j = i + 1; j < parentArray.length - i; j++) {
let difference = parentArray[i].filter(x => !parentArray[j].includes(x))
if (difference.length > 0) {
distinct += 1;
}
}
}
return distinct;
}
Here is how you could have tried. Try converting the inner arrays to a string, then filter the dupes and parse the string again
var pp = [[1, 2], [1, 2] ,[3, 4] ,[5, 6]];
var distict = pp.map(ar=>JSON.stringify(ar))
.filter((itm, idx, arr) => arr.indexOf(itm) === idx)
.map(str=>JSON.parse(str));
console.log(distict.length);
Basically I need to do this: take x element of each array in a 2D array and push that to the x element of a different array.
I'm not getting any syntax errors but my program stops running (but console.logs on either side of this line and only the top one logged). Here's my code:
for (var i = 0; i < myArray.length; i++) {
for (var j = 0; j < myArray[i].length; j++) {
console.log("Hi")
finishedarray[i].push(myArray[i][j])
console.log("Hi x2")
}
}
How should I go about getting around this?
FlatMap
What you want to do is called flat mapping. Way to built a flatMap functionality is to use reduce in combination with spread operator or Array.concat like this:
Reduce + Spread/Concat
ES2015
const myArray = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
const finishedArray = myArray
.reduce((combinedArr, currentArr) => ([...combinedArr, ...currentArr]), []);
console.log(finishedArray); // Prints: [1, 2, 3, 4, 5, 6, 7, 8, 9]
ES5
var myArray = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var finishedArray = myArray
.reduce(function (combinedArr, currentArr) {
return combinedArr.concat(currentArr);
}, []);
console.log(finishedArray); // Prints: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Array.flat
var myArray = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var finishedArray = myArray.flat();
console.log(finishedArray); // Prints: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Bugfix to your solution
Your code should work with a slight bug fix as well. The problem in your code is that you try to push an entry to finishedarray[i] - but you have an empty array and access position i, which returns undefined. Just push to the array directly:
for-Loop
for (var i = 0; i < myArray.length; i++) {
for (var j = 0; j < myArray[i].length; j++) {
finishedarray.push(myArray[i][j]); // removed the "[i]" part in front of ".push"
}
}
for...of Loop
for (var arr of myArray) {
for (var entry of arr) {
finishedarray.push(entry);
}
}
Edit: Added Array.flat. Thanks for the comment pointing to that!
I have an array which is like that: [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]]
And I want to accumulative the second values: [[0, 50], [1, 90], [2, 120], [3, 140], [5, 150]]
I tried the code part below which works for one dimensional arrays, but it doesn't work for 2d arrays. Is it possible to accumulate it by using reduce function? Or is there different way to do it?
var array1 = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]];
var newArray1 = [];
array1.reduce(
function (previousValue, currentValue, currentIndex) {
return newArray1[currentIndex] = [currentIndex, (previousValue[1] + currentValue[1])];
}, 0
);
You can use map() with optional thisArg parameter
var array1 = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]];
var result = array1.map(function(e) {
this.num = (this.num || 0) + e[1];
return [e[0], this.num];
}, {});
console.log(result);
Use Array#reduce method
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
// initialize as the array of first element in original array
var newArray1 = [array1[0].slice()];
array1
// get remaining array element except first
.slice(1)
// iterate over the array value to generate result array
.reduce(function(arr, v, i) {
// copy the array element if you don't want to refer the old
v = v.slice();
// add previous array value
v[1] += arr[i][1];
// push updated array to result array
arr.push(v);
// retur the updated array
return arr;
// set initial value as array which contains first element(array) copy
},newArray1);
console.log(newArray1)
UPDATE 1: Another method with less code
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
var newArray1 = [array1[0].slice()];
array1.slice(1).reduce(function(arr, v, i) {
arr.push([v[0], v[1] + arr[i][1]]);
return arr;
}, newArray1);
console.log(newArray1)
UPDATE 2 : Much more reduced version without using Array#slice method.
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
var newArray1 = array1.reduce(function(arr, v, i) {
// push value to array add value only if `arr` contains any element
arr.push([v[0], v[1] + (arr.length && arr[i - 1][1])]);
return arr;
// set initial value as an empty array
}, []);
console.log(newArray1)
Just for fun lets invent a new array functor, Array.prototype.extend() This works like opposite to the reduce. It takes an array and extends it starting from the last item by utilizing a provided callback. When the callback returns undefined it sops extending. Let see how we can have fun with it in this particular case;
Array.prototype.extend = function(cb){
var len = this.length + 1,
res = cb(this[len-1], len-1, this);
return res ? this.extend(cb) : this;
};
var arr = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]],
cb = function(e,i,a){
return i === 0 ? a.push(arr[i])
: i < arr.length ? a.push([arr[i][0], arr[i][1] + a[i-1][1]])
: void 0;
};
result = [].extend(cb);
console.log(result);
Let's say I have two arrays:
var a = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 10]];
var b = [[1, 20], [3, 20], [4, 20]];
I want to combine these two into a new array:
var c = [[1, 10, 20], [2, 10], [3, 10, 20], [4, 10, 20], [5, 10]];
What's the best way to go about doing this. I'll update my question in a second with what I've tried to do.
var c = [];
for(var i = 0; i < a.length; i++) {
for(var j = 0; j < b.length; j++) {
if(a[i][0] == b[j][0]) {
// Push b value into a
a[i][0].push(b[j][1]);
} else {
// Don't do anything...
}
}
}
c = a; // Useless code here but just wanted to return c
return c;
Example
var a = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 10]];
var b = [[1, 20], [3, 20], [4, 20]];
var c = [];
// Loop over a
for (var n = 0; n < a.length; n++) {
// Create copy of a's value
var subA = a[n].slice(0);
// Loop over b
for (var i = 0; i < b.length; i++) {
var subB = b[i];
// Check if a contains b
if (subA.indexOf(subB[0]) === 0) {
// Add b to new a value
subA.push(subB[1]);
}
}
// Add new value to c
c.push(subA);
}
console.log(a)
console.log(c);
Edit 1: updated for loop
Edit 2: If first item equals first item
Edit 3: Slice a to retain original values
Why don't you use plain arrays? They can be sparse.
var a = [10, 10, 10, 10, 10];
var b = [20, , 20, 20];
Now get them into one array:
var c = new Array(Math.max(a.length, b.length));
for (var i=0; i<c.length; i++)
if (i in a && i in b)
c[i] = [a[i], b[i]];
else if (i in a)
c[i] = [a[i]];
else if (i in b)
c[i] = [b[i]];
For the case that your objects (the items really don't have to be arrays) consist of a non-integer indexing values, you might use a simple standard merge algorithm on the two sorted lists. It will run in O(n+m), not in O(n*m) as your solution. See this answer for an example implementation and further pointers.