I have an array like this
var a= [[1, 2, [6, 7, 8]], 4, 5];
and another array that indicates a specific element by describing the index:
var index= [0, 2, 2 ]; // = 8 in a
What i need is use variable "index" to create the index of "a" and replace the correspondent element (8) with another value, for example "hello".
How can i do?
Use Array.reduce() to iterate the index array without the last element (using Array.slice()), and get the sub array. Splice the text to last index inside the sub array:
const index = [0, 2, 2 ]; // = 8 in a
const a = [[1, 2, [6, 7, 8]], 4, 5];
const updateIndex = (arr, index, replacement) => {
index
.slice(0, -1)
.reduce((c, i) => c[i], arr)
.splice(index[index.length -1], 1, replacement);
}
updateIndex(a, index, 'hello');
console.log(a);
Basically each index of index array represents a level of nesting and the value at index represents the index of array in which target element lies or the index of target element itself if it is last element of array index. The problem can be easily solved recursively
For simplicity, I am calling index array, path
var path = [0, 2, 2]
var values = [[1, 2, [6, 7, 8]], 4, 5];
function findValues(path, values) {
//base case, if length = 1 we have the index of target element
if(path.length == 1) {
var targetIndex = path[0]
//read it
console.log(values[path]) //8
// modify it
values[path] = 'hello'
} else {
// pick the current nesting level
var currentLevel = path.shift()
// go one level down
findValues(path, values[currentLevel])
}
}
findValues(path, values)
console.log(values) // [[1, 2, [6, 7, "hello"]], 4, 5]
Ofcouse the function assumes that path and values array are in valid state i.e. target element exists on the given path, you might want to modify this function to validate input and handle edge cases
You can create a function that accesses the desired array and changes the value.
Take a look:
var index = [0, 2, 2 ]; // = 8 in a
var a = [[1, 2, [6, 7, 8]], 4, 5];
function updateIndex(arr, index, value) {
var elementIndex = index.pop();
var tempArray = a;
index.forEach(item => tempArray = tempArray[item]);
tempArray[elementIndex] = value;
}
updateIndex(a, index, 'hello');
console.log(a);
You could take a function which uses a vopy of indices and save the last index for accessing the reduced array for assignment of the value.
This proposal creates missing arrays as well.
function setValue(array, [...indices], value) {
var last = indices.pop();
indices.reduce((a, i) => a[i] = a[i] || [], array)[last] = value;
}
var array = [[1, 2, [6, 7, 8]], 4, 5];
setValue(array, [0, 2, 2 ], 'hello'); // targetting 8
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
Let's say I have 4 arrays:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
And I want to return the child/sub arrays that start with both 1 and 2, what type of loop would I need?
Currently, this is what I have:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2]; // These are the values that need to match
var result = [];
for (var i = 0; i < selected.length; i++) {
for (var j = 0; j < arrays.length; j++) {
if (arrays[i][j] === selected[i]) {
result.push(arrays[i]);
}
}
}
When there's more than 1 value in the selected array, it seems to return all the ones that match 2 on the second index, so the result would be:
[
[1, 2, 1],
[1, 2, 3],
[0, 2, 2]
]
The loop needs to ensure that on the second iteration it's making sure the first value is still true, as my intended result would be:
[
[1, 2, 1],
[1, 2, 3]
]
Please someone help me, I've had my head trying hundreds of different loop and checks variations for 2-3 days.
Thanks so much!!
Jake
Your current code pushes to the result array whenever any given index matches between arrays and selected. Instead you will need to reverse your loops and iterate over selected for every sub array and check if every element matches, if not break the inner loop and don't push.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
const selected = [1, 2]; // These are the values that need to match
const result = [];
for (let i = 0; i < arrays.length; i++) {
let match = true;
for (let j = 0; j < selected.length; j++) {
if (arrays[i][j] !== selected[j]) {
match = false;
break;
}
}
if (match) {
result.push(arrays[i]);
}
}
console.log(result);
A more modern solution would be to use filter() with a nested every() call on selected.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
var selected = [1, 2];
const result = arrays.filter(arr => selected.every((n, i) => n === arr[i]));
console.log(result);
Here is another approach where you turn both arrays to string and check it those inner arrays start with selected array.
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2];
const result = arrays.filter(e => e.toString().startsWith(selected.toString()))
console.log(result)
Let's try to put your condition into words. That way, an implementation may come to mind more easily.
A short wording may be: "Take all arrays that match (rather: start with) a certain sub-array." In code, it may look like this:
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
const selection = [1, 2];
const result = filterArrays(arrays, selection);
console.log(result);
function filterArrays(arrays, selection) {
const selectedArrays = [];
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
const subarray = array.slice(0, selection.length); // Get starting sub-array
if (compareArrays(subarray, selection)) {
selectedArrays.push(array);
}
}
return selectedArrays;
}
/*Ignore; helper function*/
function compareArrays(array1, array2) {
if (array1.length !== array2.length) return false;
const length = array1.length;
for (let i = 0; i < length; ++i) {
if (array1[i] !== array2[i]) return false;
}
return true;
}
.as-console-wrapper {max-height:100%!important}
Another, more specific wording may be: "Take all arrays that match a selection at an index." Note that we only reworded the "match a sub-array" part. I believe this is what you tried.
Refer to pilchard's answer for an implementation. Note that their implementation assumes the arrays in arrays to be at least the same length as selected.
I see you used var instead of the preferred modern let/const declarators. Here's a short outline of their differences:
let/const declarators:
Block-scoped.
Narrower scope means less name-space pollution.
More similar to declarators in other well-known languages:
Variables of these declarators cannot be used before their declaration (see TDZ).
var declarator:
Function-scoped.
Hoisted and with no TDZ, resulting in this (perhaps confusing) behaviour:
Variables declared with var can be used even before their declaration.
Duplicate declarations are allowed since they are effectively the same.
Also, JavaScript has different kinds of for-loops:
for-loop: The for-loops you used are this kind. It is the most versatile kind.
for...of-loop: A loop to iterate over an iterable object (see iterators). For example, arrays are iterable, so you can get its values with a for...of-loop:
const values = [1, 2, 3];
let sum = 0;
for (const value of array) {
sum += value;
}
console.log(sum); // -> 6
for...in-loop: A loop to iterate over enumerable properties of an object. It is easily confused with a for...of-loop, but MDN's example demonstrates the differences understandably.
In my code example above, the for-loop in filterArrays() can be replaced with a for...of-loop to better convey my intention: To iterate over all arrays in arrays, disregarding their index:
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
// ...
}
// Same as
for (const array of arrays) {
// ...
}
I have an Array, arr = [2,4,8,7,3,6] I want to make each element of it be summation when the result is 10 , then save the element it would be arranged to another array.
make the element that result is 10 close each other like 2 and 8, add to another element named arr2.
result i need : arr2[2,8,3,7,4,6]
my code :
const arr = [2, 4, 8, 7, 3, 6];
let arr2 = [];
for (let i = 0; i < arr.length(); i++) {
let Number1 = arr[i];
let Number2 = arr[(i + 1)];
if (Number1 + Number2 === 10) {
let element1 = arr.indexOf(Number1);
let element2 = arr.indexOf(Number2);
arr2.push(element1, element2);
}
console.log(arr2[i]);
}
someone can solve my problem please ?
If you need to create arr2 so that the items sum up to 10 you can make use of a simple map here:
const arr = [2, 4, 8, 7, 3, 6];
const arr2 = arr.map((item) => 10 - item)
console.log(arr2);
You should first loop through the array to create a dictionary of value to index, then loop the array again and lookup for the complement of the current value to the target. If it exist then yes you got the answer.
.filter(x => x > i) is to search for complement that has higher index than current one so that we will not get duplicated result pushed. For example input is [2, 8], you don't want to get [2, 8, 8, 2]
Here is my solution
const arr = [2, 4, 8, 7, 3, 6];
let arr2 = [];
function solution(target: number, input: number[]): number[] {
const result: number[] = [];
const lookUpMap: {[key: number]: number[]} = {};
let i = 0;
for (const each of input) {
if (!(each in lookUpMap)) {
lookUpMap[each] = [];
}
lookUpMap[each].push(i);
i++;
}
i = 0;
for (const each of input) {
const difference = target - each;
if (difference in lookUpMap) {
const complementIndex = lookUpMap[difference].filter(x => x > i)[0];
if (complementIndex) {
result.push(input[i], input[complimentingIndex]);
}
}
i++;
}
return result;
}
arr2 = solution(10, arr);
console.log(arr2);
Assuming a valid result can be created for the given arr. A fairly simple solution would be to sort the array first. Then step through half the array and take the element on the current index, and the element on the inverse index (length - 1 - index). And push() those both in the resulting array.
So here in steps, given you have the following array:
[2, 4, 8, 7, 3, 6]
You sort it:
[2, 3, 4, 6, 7, 8]
Then you step through half the indexes and take each element, and the element on the inverse index.
[2, 3, 4, 6, 7, 8]
// \ \ \/ / /
// \ ------ / -> [2, 8, 3, 7, 4, 6]
// ----------
const arr = [2, 4, 8, 7, 3, 6];
const sortedArr = Array.from(arr).sort((a, b) => a - b); // ascending
const length = sortedArr.length;
const nPairs = length / 2;
const arr2 = [];
for (let i = 0; i < nPairs; ++i) {
arr2.push(
sortedArr[i],
sortedArr[length - 1 - i],
);
}
// or if you want a more functional approach:
// const arr2 = Array.from({ length: nPairs }).flatMap((_, i) => [sortedArr[i], sortedArr[length - 1 - i]]);
console.log(arr2);
Do note that this is probably not the fastest solution, because sorting is non-linear.
Obviously this solution does not work if an invalid input is given, like [7,2,1,8] which can never produce a valid output.
I am trying to write an JS algorithm in which I have two arrays.
The value of the first one will have different numerical values. The second array will be constant, say for example [5, 3, 6, 8].
Now I would like to multiply the values from the first array, by the corresponding index value from the second array, so having for example such a first array: [3, 7, 2, 5] it would look like this: 5*3, 3*7, 6*2, 8*5.
From the result I would like to create a new array, which in this case is [15, 21, 12, 40].
How can I achieve this result?
You can use map() and use the optional parameter index which is the index of the current element being processed in the array:
const arr1 = [3, 4, 5, 6];
const arr2 = [7, 8, 9, 10];
const mulArrays = (arr1, arr2) => {
return arr1.map((e, index) => e * arr2[index]);
}
console.log(mulArrays(arr1, arr2));
This is assuming both arrays are of the same length.
You can simply use for loop -
var arr1 = [5, 3, 6, 8];
var arr2 = [3, 7, 2, 5];
var finalArr = [];
for (var i = 0; i < arr1.length; i++) {
finalArr[i] = arr1[i] * arr2[i];
}
console.log(finalArr);
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.
I have a function using an array value represented as
markers[i]
How can I select all other values in an array except this one?
The purpose of this is to reset all other Google Maps images to their original state but highlight a new one by changing the image.
Use Array.prototype.splice to get an array of elements excluding this one.
This affects the array permanently, so if you don't want that, create a copy first.
var origArray = [0,1,2,3,4,5];
var cloneArray = origArray.slice();
var i = 3;
cloneArray.splice(i,1);
console.log(cloneArray.join("---"));
You can use ECMAScript 5 Array.prototype.filter:
var items = [1, 2, 3, 4, 5, 6];
var current = 2;
var itemsWithoutCurrent = items.filter(function(x) { return x !== current; });
There can be any comparison logics instead of x !== current. For example, you can compare object properties.
If you work with primitives, you can also create a custom function like except which will introduce this functionality:
Array.prototype.except = function(val) {
return this.filter(function(x) { return x !== val; });
};
// Usage example:
console.log([1, 2, 3, 4, 5, 6].except(2)); // 1, 3, 4, 5, 6
You can also use the second callback parameter in Filter:
const exceptIndex = 3;
const items = ['item1', 'item2', 'item3', 'item4', 'item5'];
const filteredItems = items.filter((value, index) => exceptIndex !== index);
You can use slice() Method
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1,3);
The slice() method returns the selected elements in an array, as a new array object.
This function will return a new array with all elements except the element at the specified index:
const everythingBut = (array, i) => { /*takes an array and an index as arguments*/
let notIArray = []; /*creates new empty array*/
let beforeI = array.slice(0, i); /*creates subarray of all elements before array[i]*/
let afterI = array.slice(i+1,); /*creates subarray of all elements after array[i]*/
notIArray = [...beforeI, ...afterI]; /*add elements before and after array[i] to empty array*/
return notIArray; /*returns new array with array[i] element excluded*/
};
For example:
let array = [1, 2, 4, 7, 9, 11, 2, 6]
everythingBut(array, 2); /*exclude array[2]*/
// -> [1, 2, 7, 9, 11, 2, 6]
Another way this can be done is by using filter and slice Array methods.
let array = [ 1, 2, 3, 4, 5, 6 ];
let leave = 2;
// method 1
console.log(array.filter((e,i) => i !== leave));
// logs [1, 2, 4, 5, 6];
//method 2
console.log([...array.slice(0, leave), ...array.slice(leave+1, array.length)]);
// logs [1, 2, 4, 5, 6];
You can combine Array.prototype.slice() and Array.prototype.concat() in using startingArray.slice(desiredStartIndex, exclusionIndex).concat(startingArray.slice(exclusionIndex+1)) to exclude the item whose index is exclusionIndex.
E.g., if you have a startingArray of [0, 1, 2] and want a desiredArray of [0, 2], then you can do as follows:
startingArray = [0, 1, 2];
desiredStartIndex = 0;
exclusionIndex = 1;
desiredEndIndex = 2;
desiredArray = startingArray.slice(desiredStartIndex,
exclusionIndex).concat(startingArray.slice(exclusionIndex+1));
With ECMAScript 5
const array = ['a', 'b', 'c'];
const removeAt = 1;
const newArray = [...array].splice(removeAt, 1);