Searching for an object inside an array of arrays - javascript

i have an array, filled with arrays, each containing multiple objects. I want to see if my objects exists in there
Ive made a jsfiddle to keep it simple - https://jsfiddle.net/rgnoz31y/1/
Or if you want to just see my code, its below:
blackChains = [];
blackChains.push([{x: 1, y: 2}, {x: 1, y: 3}]);
blackChains.push([{x: 3, y: 4}, {x:4, y: 4}, {x:5, y: 4}]);
currentPiece = {x: 1, y: 3};
const isInChain = blackChains.map(g => g[{}]).includes(currentPiece);
console.log(isInChain);
It currently returns false, when it should be true

As you are using Arrow functions, I assumed you are using ES6.
Using Spreads, I can create an array of all the Array Items https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_operator
acc.push(...item);
includes would usually work, however it only works on call by reference, not call by value e.g. this would have failed:
console.log([{x: 1, y: 2}, {x: 1, y: 3}].includes(currentPiece));
Some returns true, if at least one of the items matches the condition. By changing the Item and Search Element into a JSON String, we can check by Value.
blackChains = [];
blackChains.push([{x: 1, y: 2}, {x: 1, y: 3}]);
blackChains.push([{x: 3, y: 4}, {x:4, y: 4}, {x:5, y: 4}]);
currentPiece = {x: 1, y: 3};
const isInChain = blackChains.reduce((acc, item) => {
acc.push(...item);
return acc;
}, []).some(item => JSON.stringify(item) === JSON.stringify(currentPiece));
console.log(isInChain);

As commented before,
g[{}] will return undefined. It is interpreted as g["Object object"]
blackChains.map(g => g[{}]) will return an array of length n with all as undefined.
You can use recursion to loop over r nested arrays and stop it when you get Objects.
var blackChains = [];
blackChains.push([{x: 1, y: 2}, {x: 1, y: 3}]);
blackChains.push([{x: 3, y: 4}, {x:4, y: 4}, {x:5, y: 4}]);
var currentPiece = { x: 1, y: 3 };
function searchObjInArray(arr, search) {
if (Array.isArray(arr)) {
return arr.some(function(item) {
return searchObjInArray(item, search)
})
} else if (typeof arr === "object") {
var valid = true;
for (var k in search) {
valid = valid && search[k] === arr[k];
if (!valid) break;
}
return valid;
}
}
var isInChain = searchObjInArray(blackChains, currentPiece)
console.log("isInChain: ", isInChain);
currentPiece.y = 4;
isInChain = searchObjInArray(blackChains, currentPiece)
console.log("isInChain: ", isInChain);

Simply Try with Array#filter() and Array#find() used find the match with c Array
function check(c){
blackChains = [];
blackChains.push([{x: 1, y: 2}, {x: 1, y: 3}]);
blackChains.push([{x: 3, y: 4}, {x:4, y: 4}, {x:5, y: 4}]);
return blackChains.filter(a=> a.find(a=> a.x == c.x && a.y == c.y ))[0] ? true : false;
}
console.log(check({x: 1, y:3}))
console.log(check({x: 1, y:31}))

Replace with:
const isInChain = blackChains.findIndex(
i => i.findIndex(a => a.x === currentPiece.x && a.y === currentPiece.y) > -1) > -1;

You need to check key-value equality explicitly as shown below:
blackChains = [];
blackChains.push([{x: 1, y: 2}, {x: 1, y: 3}]);
blackChains.push([{x: 3, y: 4}, {x:4, y: 4}, {x:5, y: 4}]);
currentPiece = {x: 1, y: 3};
const isInChain = blackChains.map(bc => !!bc.find(o => // return true a false for each index
Object.keys(o).every(key => o[key] === currentPiece[key])));
console.log(isInChain);

Related

Replace value of nested object with variable structure

I've an object like this:
const obj = {a: {x: 0, y: 0}}
that could be also:
const obj = {a: {x: 0, y: 0}, b: {x: 10, y: 3}, abcd: {x: -1, y: 0}}
So, the obj can have more than one key and with variables key names.
I need to replace each x value with a a string like this ${x}% so the x value + the percentage symbol.
How can I do that?
The expected results should be:
const obj = {a: {x: 0, y: 0}} // {a: {x: '0%', y: 0}}
const obj = {a: {x: 0, y: 0}, b: {x: 10, y: 3}, abcd: {x: -1, y: 0}} // {a: {x: '0%', y: 0}, b: {x: '10%', y: 3}, abcd: {x: '-1%', y: 0}}
I tried looping the object but I don't know if there is a smartest solution
const obj = {a: {x: 0, y: 0}, b: {x: 10, y: 3}, abcd: {x: -1, y: 0}}
let result = Object.fromEntries(Object.entries(obj).map(([k,v]) => {
return [k,{...v,x:`${v.x}%`}]
}))
console.log(result)
You can also check the object recursively. So no matter how deep the object goes every given key that matches gets a suffix.
I also make sure to create a copy of the object to prevent altering the original object(s).
const obj = {a: {x: 0, y: 0}, b: {x: 10, y: 3}, abcd: {x: -1, y: 0}};
const addSuffixToObj = (obj, key, suffix) => {
const copy = {...obj};
Object.keys(copy).forEach((prop) => {
if (typeof copy[prop] === 'object') {
copy[prop] = addSuffixToObj(copy[prop], key, suffix);
}else if(prop === key){
copy[prop] = copy[prop] + suffix;
}
});
return copy;
}
// Add "%" to all "x" keys
const result = addSuffixToObj(obj, 'x', '%');
console.log(result);
You can get the array of object keys and then use forEach, it's a method that executes provided function for every element of array(here - for every object key):
Object.keys(obj).forEach(el => obj[el].x = `${obj[el].x}%`)

Aggregate an array of objects in JavaScript

I have an array of objects having a boolean field X. [{..., x: true, y: 3, ...]
I need to aggregate this array, in order to obtain a value, true(or false), if all values of x are correspondingly true(or false), otherwise undefined... and a sum of y's...
is that possible to use the reduce Array function, groupby by underscorejs, or another one for this purpose?
ex:
[
{a:'titi', x: true, y: 3},
{a:'toto', x: false, y: 6}
]
result
{x: undefined, y: 9}
this is pretty straight-forward with reduce:
.reduce((a, b) => ({
x: a.x == b.x ? a.x : undefined,
y: a.y + b.y
}))
Live example:
var input = [
{a:'titi', x: true, y: 3},
{a:'toto', x: false, y: 6}
];
console.log(input.reduce((a, b) => ({
x: a.x == b.x ? a.x : undefined,
y: a.y + b.y
})));
Although you can shoehorn this into a reduce call (because any array operation can be shoehorned into a reduce), there's no benefit to doing so. Just use a loop:
const result = {x: null, y: 0};
for (const entry of array) {
if (result.x === null) {
result.x = entry.x;
} else if (result.x !== entry.x) {
result.x = undefined;
}
result.y += entry.y;
}
Live Example:
function check(array) {
const result = {x: null, y: 0};
for (const entry of array) {
if (result.x === null) {
result.x = entry.x;
} else if (result.x !== entry.x) {
result.x = undefined;
}
result.y += entry.y;
}
console.log(result);
}
check([
{a:'titi', x: true, y: 3},
{a:'toto', x: false, y: 6}
]);
console.log("---");
check([
{a:'titi', x: true, y: 3},
{a:'toto', x: true, y: 6}
]);
console.log("---");
check([
{a:'titi', x: false, y: 3},
{a:'toto', x: false, y: 6}
]);
console.log("---");
But again, you can shoehorn that into a reduce if you want by always returning the same object:
const result = array.reduce((obj, entry) => {
if (obj.x === null) {
obj.x = entry.x;
} else if (obj.x !== entry.x) {
obj.x = undefined;
}
obj.y += entry.y;
return obj;
}, {x: null, y: 0});
Live Example:
function check(array) {
const result = array.reduce((obj, entry) => {
if (obj.x === null) {
obj.x = entry.x;
} else if (obj.x !== entry.x) {
obj.x = undefined;
}
obj.y += entry.y;
return obj;
}, {x: null, y: 0});
console.log(result);
}
check([
{a:'titi', x: true, y: 3},
{a:'toto', x: false, y: 6}
]);
console.log("---");
check([
{a:'titi', x: true, y: 3},
{a:'toto', x: true, y: 6}
]);
console.log("---");
check([
{a:'titi', x: false, y: 3},
{a:'toto', x: false, y: 6}
]);
console.log("---");
But, if you want a reduce solution and you don't mind creating a bunch of temporary throw-away objects, check out Adassko's answer. Simple and straight-forward, and 99.9% of the time, you don't care about the temporary object creation.
I came up with this solution using reduce. Seems kind of hacky, but it should do the job. While reducing the array it determines if every x-value is equal, afterwards it sets the x-value of the reduced object accordingly.
let reduced = arr.reduce((acc, curr) => {
acc.x &= acc.x_init === curr.x;
acc.y += curr.y;
}, {x_init: arr[0].x, x: true, y: 0});
reduced.x = reduced.x ? reduced.x_init : undefined;
delete reduced.x_init;
thanks #Adassko, my variant was a little bit longer:
[
{a:'titi', x: false, y: 3},
{a:'toto', x: false, y: 6}
]
.reduce((a, b, i) => ({
x : a.x === b.x || i == 0 ? b.x : undefined,
y : a.y + b.y
}))

Merge objects in array with similar key

I have an array of objects:
objArray = [
{x: 1, y: 7},
{x: 2, y: 14},
{x: 1, z: 9},
{x: 2, z: 18}
{x: 1, n: 6}
{x: 2, n: 16}
]
Is there an efficient way to merge for "X" without a for loop? so that I end up with:
objArray = [
{x: 1, y: 7, z: 9, n: 6},
{x: 2, y: 14, z: 18, n: 16}
]
So look for common objArray[n]["x"] and merge all hits into one object? It's OK to modify the original array or create a new one.
I'm aware this can be done with a loop, but I'm trying to avoid too many loops for this implementation, though I'm not sure if a reduce or a filter would work for this.
You could take a Map and group by property x.
var array = [{ x: 1, y: 7 }, { x: 2, y: 14 }, { x: 1, z: 9 }, { x: 2, z: 18 }, { x: 1, n: 6 }, { x: 2, n: 16 }],
result = Array.from(
array
.reduce((m, o) => m.set(o.x, Object.assign({}, m.get(o.x), o)), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use reduce method to build an object and then Object.values to get an array.
const data = [{"x":1,"y":7},{"x":2,"y":14},{"x":1,"z":9},{"x":2,"z":18},{"x":1,"n":6},{"x":2,"n":16}]
const res = data.reduce((r, {x, ...rest}) => {
if(!r[x]) r[x] = {x, ...rest}
else Object.assign(r[x], rest);
return r;
}, {})
const result = Object.values(res);
console.log(result)
You can do it with Array#reduce:
const objArray = [
{x: 1, y: 7},
{x: 2, y: 14},
{x: 1, z: 9},
{x: 2, z: 18},
{x: 1, n: 6},
{x: 2, n: 16},
]
const result = Object.values( objArray.reduce(
(p,c) => (p[c.x] = Object.assign( {}, p[c.x], c ), p ), {}
) );
console.log( result );

find index of max value of associate array in jquery [duplicate]

This question already has answers here:
Find maximum value of property in object of objects
(3 answers)
Closed 5 years ago.
i have an array like this,and want to find index of maximum of value .for this sample it should return c1:
var arr={
c1:{val: 9, x: 2, y: 0}
c2:{val: 1, x: 3, y: 0}
c3:{val: 6, x: 4, y: 0}
}
var arr=[{val: 9, x: 2, y: 0},
{val: 1, x: 3, y: 0},
{val: 6, x: 4, y: 0}
];
var max_value = arr.reduce((a,b)=> (a.x+a.y+a.val) > (b.x+b.y+b.val) ? a:b )
// or if it is the index that you want :
var max_index = arr.reduce((a,b,i,_)=> (_[a].x+_[a].y+_[a].val) > (b.x+b.y+b.val) ? a:i, 0);
console.log(max_value);
console.log(max_index);
Assuming your array is
var arr = [
{val: 9, x: 2, y: 0}, {val: 1, x: 3, y: 0}, {val: 6, x: 4, y: 0},
];
You can get the max value by using Math.max.apply and map
var output = Math.max.apply( null, arr.map( c => c.val ) )
Or if it is an object (as per your latest update)
var arr = {
c1:{val: 9, x: 2, y: 0},
c2:{val: 1, x: 3, y: 0},
c3:{val: 6, x: 4, y: 0}
};
var maxValue = Math.max.apply( null, Object.values( arr ).map( c => c.val ) )
You can get the index-Of the maxValue by doing
var output = Object.keys(arr).findIndex( s => arr[s].val == maxValue );

How to update hashmap field by dynamic key using Object.assign and avoid mutations?

How do i define updater to get true in newState.c.x === 8 and avoid any mutation in state?
var state = {
a: {x: 1, y: 1},
b: {x: 2, y: 2},
c: {x: 3, y: 3},
d: {x: 4, y: 4},
};
var key = 'c';
var x = 8;
var updater = {
//Having state, key and x here....
}
var newState = Object.assign({}, state, updater);
if(newState.c.x === 8) {
wooHoo();
}
Thanks in advance!
You can use some ES6 destructuring and Object.assign().
var state = {
a: {x: 1, y: 1},
b: {x: 2, y: 2},
c: {x: 3, y: 3},
d: {x: 4, y: 4},
};
var key = 'c';
var x = 8;
var updater = {
[key]: Object.assign({}, state[key], {x})
}
var newState = Object.assign({}, state, updater);
if(newState.c.x === 8) {
alert('True')
}

Categories