I've searched high and low for an answer to this, but nothing.
I have a nested array and want to find it by exact value but can't seem to get it to work:
let rowLetters = ["A","B","C",["D","E"],"F"];
for(n=0;n<rowLetters.length;n++){
if(rowLetters[n] === ["D","E"]){
console.log("Found");
}
console.log(rowLetters[n]);
}
Console Output:
"A"
"B"
"C"
["D","E"] // <-- There it is..
"F"
What am I doing wrong?
You need to check
if item is an array,
if item has the same length as the wanted value array and
if the values of the arrays are equal.
let rowLetters = ["A", "B", "C", ["D", "E"], "F"],
search = ["D", "E"];
for (const item of rowLetters) {
if (Array.isArray(item) && item.length === search.length && search.every((v, i) => item[i] === v)) {
console.log(item);
}
}
You can use filter with JSON.stringify()
let data = ["A", "B", "C", ["D", "E"], "F"];
let search = data.filter(ele => JSON.stringify(ele) == JSON.stringify(["D", "E"]));
if (search.length > 0) {
console.log("found")
}
Are you looking for something like find() mixed with Array.isArray()?
let rowLetters = ["A","B","C",["D","E"],"F"];
console.log(rowLetters.find(i => Array.isArray(i)))
You cannot compare an array to an array because you are comparing by a reference and not a value. You can however cast the value to a json string and compare, however, this requires exact order in both arrays.
let rowLetters = ["A","B","C",["D","E"],"F"];
for(let i of rowLetters){
if(JSON.stringify(i) === JSON.stringify(["D","E"])) {
console.log("Found");
}
}
You can use .find and JSON.stringify:
let rowLetters = ["A","B","C",["D","E"],"F"];
let arrayToFind = JSON.stringify(["D","E"])
let nestedArray = rowLetters.find( arr => JSON.stringify(arr) === arrayToFind );
console.log(nestedArray);
A better way to check if two arrays are equal would be using .every and .includes as follows:
let rowLetters = ["A","B","C",["D","E"],"F"];
const arraysAreEqual = (arr1, arr2) => {
if(arr1.length != arr2.length) return false;
return arr1.every( e => arr2.includes(e) );
}
const arrayToFind = ["D","E"];
let nestedArray = rowLetters.find( arr => arraysAreEqual(arr, arrayToFind) );
console.log(nestedArray);
Related
I'm trying to filter arr2. If the element doesn't have an ID listed in arr, then I want it to be removed. How could I make this happen in javascript?
var arr= ["a", "b", "d"]
var arr2=[{id:"a", value:1},{id:"b", value:2}, {id:"c", value:3}]
result:
[{id:"a", value:1},{id:"b", value:2}]
Thanks in advance :)
You can use reduce and in the callback function check if arr includes the id of the object under iteration. If so then add the elements in the accumulator array
var arr = ["a", "b", "d"]
var arr2 = [{
id: "a",
value: 1
}, {
id: "b",
value: 2
}, {
id: "c",
value: 3
}];
const newData = arr2.reduce((acc, curr) => {
if (arr.includes(curr.id)) {
acc.push(curr)
}
return acc;
}, []);
console.log(newData)
if arr items are always strings you can do this:
var arr = ["a", "b", "d"];
var arr2 = [{id:"a", value:1},{id:"b", value:2}, {id:"c", value:3}];
let str = arr.join('')
let filtered = arr2.filter(x => str.includes(x.id));
console.log(filtered)
this should do it
var arr= ["a", "b", "d"]
var arr2=[{id:"a", value:1},{id:"b", value:2}, {id:"c", value:3}]
const filteredArray = arr2.filter(obj => {
return arr.includes(obj.id)
})
Using filter, reduce, and includes are all nearly twice as slow as simply using a loop. To walk you through it, all it does is check over every element in the second array and check to see if it's id property is in the first array, and if it is, it clones it. Also, for future reference, that title is written poorly. A much better title would be "How to filter array of objects based on a list of possible ID properties"
var arr= ["a", "b", "d"]
var arr2=[{id:"a", value:1},{id:"b", value:2}, {id:"c", value:3}]
let clone = []
for(let i = 0;i < arr2.length;i++){
for(let j = 0;j < arr.length; j++) if(arr2[i].id === arr[j]) clone.push(arr2[j])
}
console.log(clone)
I wanna create a nested object dynamically. I can create it hard coded. Is it possible to do this with a loop ?
result = {}
keys = ["a", "b", "c", "d"]
result[keys[0]] = {}
result[keys[0]][keys[1]] = {}
result[keys[0]][keys[1]][keys[2]] = {}
result[keys[0]][keys[1]][keys[2]][keys[3]] = "cool"
I want to pass an integer for example if it is "3", this should created an object like:
result = {
"a": {
"b": {
"c": "cool"
}
}
}
If it is 4, :
result = {
"a": {
"b": {
"c": {
"d": "cool"
}
}
}
}
So on ...
edit:
I am also checking result object, in order to create this nested structure. If there is not any field yet, I simply create the object.
Using this structure to group data.
Any chance to check these dynamically ?
if (!result[keys[0]])
if (!result[keys[0]][keys[1]])
if (!result[keys[0]][keys[1]][keys[2]])
You can use reduceRight() for this. It just starts from the inside at the last item in the keys list and works its way out starting with "cool":
let keys = ["a", "b", "c", "d"]
let limit = 3
let result = keys.reduceRight((obj, key) => ({[key]: obj}), "cool")
console.log(result)
To limit where the object stops you can iterate over a slice of the keys. For example:
let keys = ["a", "b", "c", "d"]
let start = 0
let stop = 3 // slices are don't inlcude the last item, so this will stop at index 2
let result = keys.slice(start, stop).reduceRight((obj, key) => ({
[key]: obj
}), "cool")
console.log(result)
simple for-loop solution.
let result = {}
let keys = ["a", "b", "c", "d"]
let depth=3;
let current = result
for(let i=0;i<depth;++i){
let key = keys[i]
if(i == depth-1) current[key] = 'cool'
else current = current[key] = {}
}
console.log(result)
If you like to add to a given object a new property, you could reduce the keys with the object and take default objects for not given keys. At the end assign the value.
function setValue(object, path, value, limit) {
var keys = path.slice(0, limit),
last = keys.pop();
keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
return object;
}
var result = { foo: 42 },
keys = ["a", "b", "c", "d"];
setValue(result, keys, 'cool');
console.log(result);
setValue(result, keys, 'cool', 3);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
short and simple using reduce
let object1= {}
keys = ['a', 'b', 'c']
keys.reduce((prev,curr,i)=>{
prev[curr] = {}
return prev[curr]
}, object1)
log(object1)
// {
// a:{
// b:{
// c:{}
// }
// }
// }
I'd use a reducer, along with some basic tests to help me out:
https://youtu.be/D6zLI8zrfVs
https://gist.github.com/brianswisher/2ce1ffe3ec08634f78aacd1b7baa31f9
Looking to search a value in an array of array and returning index. Most of the answers are array of objects. So I am looking to search for eg 22 and get 2 as the index where the value was found
Here is the code pen
https://codesandbox.io/s/lodash-playground-array-pzzhe
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log("arr", arr);
You could take plain Javascript with Array#findIndex with Array#includes.
var array = [["a", "b"], ["f", "r"], ["r", 22, "t"]],
value = 22,
index = array.findIndex(a => a.includes(value));
console.log(index);
Option 1 Use findIndex
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log(arr.findIndex(a => a.includes(22)));
Option 2: Use functions indexOf and includes:
const arr = [["a","b"],["f","r"],["r",22,"t"]];
// find element
const element = arr.find(a => a.includes(22));
// find element index
const currentIndex = arr.indexOf(element)
console.log(currentIndex);
indexOfFlat = (val, array) => array.findIndex(_arr => _arr.includes(val));
const arr = [["a","b"],["f","r"],["r",22,"t"]];
console.log("arr", arr);
console.log("index", indexOfFlat(22, arr))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.min.js"></script>
In case you would actually need the sub-array in which the value was found, you could also use Array.find and its index and get both:
const arr = [["a","b"],["f","r"],["r",22,"t"]];
let index, subArr = arr.find((x,i) => x.includes(22) && ~(index=i))
console.log('sub-array: ', subArr)
console.log('index: ', index)
There is an arrow function creating an array like:
const myFunction = () => ["a", "b", "c"];
I want to add an argument to it that must add another element if the argument is true.
Like here:
const myFunction = (arg) => ["a", "b", "c", arg ? "d" : null];
the problem with this solution is that is still adds a null element if arg !== true but I want to don't add anything in this case.
You can use array spread. According to the value of arg an empty array or an array that contains d will be spreaded into the result array:
const myFunction = (arg) => ["a", "b", "c", ...arg ? ['d'] : []];
console.log(JSON.stringify(myFunction(true))); // ["a","b","c","d"]
console.log(JSON.stringify(myFunction())); // ["a","b","c"]
You could use concat:
const myFunction = (arg) => ["a", "b", "c"].concat(arg ? ["d"] : []);
console.log(myFunction(true));
console.log(myFunction(false));
You can use Array push().
const myFunction = (arg) => {
const arr = ["a", "b", "c"];
if (arg) arr.push("d");
return arr;
};
console.log(myFunction(true));
console.log(myFunction(false));
You can make the function a bit longer,
create a temporary array,
append the element to the temporary array if required,
and return the temporary array when done
const myFunction = (arg) => {
var tempArray = ["a", "b", "c"];
if (arg) {
tempArray.push("d");
}
return tempArray;
};
console.log(myFunction(true) + "");
console.log(myFunction(false) + "");
const myFunction = (arg) => {
ret = ['a', 'b', 'c']
return arg === true ? ret.concat('d') : ret;
}
In other solutions you have arg ? instead of arg === true ?.
If you want myFunction to return array with 'd' ONLY for arg = true,then you shoulu use mine solution. If you want it to return 'd' for, for example, arg = 17, but not to return it for arg = 0, then use others solution.
You can do this also :
const myMethod = (arg) => {
var tempArray = ["item 1", "item 2", "item 3"];
!arg || tempArray.push("item 4");
return tempArray;
};
console.log(myMethod(false));
console.log(myMethod(true));
Ori has the right answer. Use that for all the modern browsers. If for some reason you're still stuck on an older browser -
["a", "b", "c"].concat(arg ? 'd' : [])
If you store your array in a variable you can make it like this:
const arr = ["a", "b", "c"];
const myFunction = arg => arg === true ? [...arr, "d"] : arr;
console.log(myFunction(true));
console.log(myFunction());
I have an array with a list of objects. I want to split this array at one particular index, say 4 (this in real is a variable). I want to store the second part of the split array into another array. Might be simple, but I am unable to think of a nice way to do this.
Use slice, as such:
var ar = [1,2,3,4,5,6];
var p1 = ar.slice(0,4);
var p2 = ar.slice(4);
You can use Array#splice to chop all elements after a specified index off the end of the array and return them:
x = ["a", "b", "c", "d", "e", "f", "g"];
y = x.splice(3);
console.log(x); // ["a", "b", "c"]
console.log(y); // ["d", "e", "f", "g"]
use slice:
var bigOne = [0,1,2,3,4,5,6];
var splittedOne = bigOne.slice(3 /*your Index*/);
I would recommend to use slice() like below
ar.slice(startIndex,length);
or
ar.slice(startIndex);
var ar = ["a","b","c","d","e","f","g"];
var p1 = ar.slice(0,3);
var p2 = ar.slice(3);
console.log(p1);
console.log(p2);
const splitAt = (i, arr) => {
const clonedArray = [...arr];
return [clonedArray.splice(0, i), clonedArray];
}
const [left, right] = splitAt(1, [1,2,3,4])
console.log(left) // [1]
console.log(right) // [2,3,4]
const [left1, right1] = splitAt(-1, [1,2,3,4])
console.log(left1) // []
console.log(right1) // [1,2,3,4]
const [left2, right2] = splitAt(5, [1,2,3,4])
console.log(left1) // [1,2,3,4]
console.log(right1) // []
Some benefits compared to other solutions:
You can get the result with a one liner
When split index is underflow or overflow, the result is still correct. slice will not behave correctly.
It does not mutate the original array. Some splice based solutions did.
There is only 1 splice operation, rather than 2 slice operations. But you need to benchmark to see if there is actual performance difference.
You can also use underscore/lodash wrapper:
var ar = [1,2,3,4,5,6];
var p1 = _.first(ar, 4);
var p2 = _.rest(ar, 4);
Simple one function from lodash:
const mainArr = [1,2,3,4,5,6,7]
const [arr1, arr2] = _.chunk(mainArr, _.round(mainArr.length / 2));
const splitArrayByIndex = (arr, index) => {
if (index > 0 && index < arr.length) {
return [arr.slice(0, index), arr.slice(-1 * (arr.length - index))]
}
}
const input = ['a', 'x', 'c', 'r']
const output = splitArrayByIndex(input, 2)
console.log({ input, output })