Related
I have two deal with two Set instances.
const set1 = new Set([
{ name: 'a' },
{ name: 'b', lastname: 'bb' },
{ name: 'c' },
{ name: 'd' },
]);
const set2 = new Set([
{ name: 'b' },
{ name: 'd' },
]);
Any object within a set will feature several and also distinct keys and values. The goal is to find structurally equal objects (same keys and values) in both sets, which is ... The intersection of equal data items in/of set1 and set2.
In the following example the expected result is [ { name: 'd' } ] ...
console.log([...set1].filter(item => set2.has(item)));
... but it logs an empty array / [] instead.
An object features more than 20 keys so one has to compare them one by one, which can not be done in a hard coded way.
How could one achieve a generic approach for an intersection of two lists of structurally equal data items?
You can do something like this:
const set1 = new Set([
{name: 'a'},
{name: 'b', lastname: 'bb'},
{name: 'c'},
{name: 'd'}
]);
const set2 = new Set([
{name: 'b'},
{name: 'd'}
]);
set1.forEach((value) => {
if (![...set2].some((o) => Object.entries(o).every(([k, v], _, arr) => (Object.keys(value).length === arr.length && value[k] === v)))) {
set1.delete(value);
}
})
console.log([...set1]);
What this does, is to iterate through set1 and if the item at the current iteration is not the same as any item in set2 (![...set2].some(..)), it is deleted.
The items are considered the same if they have the same number of keys and if the values at the same key are strictly equal.
This only works if the values of the objects in the sets are primitives, if they are not, you'll have to change value[k] === v to an appropriate comparison.
One could write a generic solution which compares pure, thus JSON conform, data structures regardless of any object's nesting depth/level and (creation time) key order.
Such a function would be self recursive for Array item (order matters) and Object property (key order does not matter) comparison. Otherwise values are compared strictly.
function isDeepDataStructureEquality(a, b) {
let isEqual = Object.is(a, b);
if (!isEqual) {
if (Array.isArray(a) && Array.isArray(b)) {
isEqual = (a.length === b.length) && a.every(
(item, idx) => isDeepDataStructureEquality(item, b[idx])
);
} else if (
a && b
&& (typeof a === 'object')
&& (typeof b === 'object')
) {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
isEqual = (aKeys.length === bKeys.length) && aKeys.every(
(key, idx) => isDeepDataStructureEquality(a[key], b[key])
);
}
}
return isEqual;
}
const objA = { // `objA` equals `objB`.
name: 'foo',
value: 1,
obj: {
z: 'z',
y: 'y',
a: {
name: 'bar',
value: 2,
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
name: 'baz',
value: 3,
obj: {
k: 'k',
i: 'i',
c: 'c',
},
arr: ['5', 6, 'B', 'A'],
}],
},
},
arr: ['Z', 'Y', 1, '2'],
};
const objB = { // `objB` equals `objA`.
arr: ['Z', 'Y', 1, '2'],
obj: {
z: 'z',
y: 'y',
a: {
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
obj: {
k: 'k',
i: 'i',
c: 'c',
},
name: 'baz',
value: 3,
arr: ['5', 6, 'B', 'A'],
}],
name: 'bar',
value: 2,
},
},
name: 'foo',
value: 1,
};
const objC = { // `objC` equals neither `objA` nor `objB`.
arr: ['Z', 'Y', 1, '2'],
obj: {
z: 'z',
y: 'y',
a: {
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
obj: {
k: 'k',
i: 'i',
c: 'C', // the single difference to `objA` and `objB`.
},
name: 'baz',
value: 3,
arr: ['5', 6, 'B', 'A'],
}],
name: 'bar',
value: 2,
},
},
name: 'foo',
value: 1,
};
console.log(
'isDeepDataStructureEquality(objA, objB) ?..',
isDeepDataStructureEquality(objA, objB)
);
console.log(
'isDeepDataStructureEquality(objA, objC) ?..',
isDeepDataStructureEquality(objA, objC)
);
console.log(
'isDeepDataStructureEquality(objB, objC) ?..',
isDeepDataStructureEquality(objB, objC)
);
console.log(
'isDeepDataStructureEquality(objB, objA) ?..',
isDeepDataStructureEquality(objB, objA)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Based on the above implementation of isDeepDataStructureEquality one can solve the OP's task, that actually looks for the intersection of two list structures, by additionally providing a getIntersectionOfDeeplyEqualDataStructures functionality ...
function getIntersectionOfDeeplyEqualDataStructures(a, b) {
return [...(a ?? [])]
.reduce((collector, sourceItem) => {
const { target, intersection } = collector;
const targetIndex = target.findIndex(targetItem =>
isDeepDataStructureEquality(targetItem, sourceItem)
);
if (targetIndex >= 0) {
// collect the intersection of
// both, source (a) and target (b).
intersection.push(target[targetIndex]);
}
return collector;
}, {
target: [...(b ?? [])],
intersection: [],
}).intersection;
}
const set1 = new Set([
{ name: 'a' },
{ name: 'b', lastname: 'bb' },
{ name: 'c' },
{ name: 'd' }
]);
const set2 = new Set([
{ name: 'b' },
{ name: 'd' },
]);
console.log(
"getIntersectionOfDeeplyEqualDataStructures(set1, set2) ...",
getIntersectionOfDeeplyEqualDataStructures(set1, set2)
);
const set3 = new Set([
{ name: 'a' },
{ name: 'b', lastname: 'bb' },
{ name: 'c' },
{
name: 'd',
list: ['foo', 1, null, false, 0, {
foo: { bar: { baz: 'bizz', buzz: '' } }
}],
},
]);
const set4 = new Set([
{
list: ['foo', 1, null, false, 0, {
foo: { bar: { buzz: '', baz: 'bizz' } }
}],
name: 'd',
},
{ name: 'C' },
{ lastname: 'bb', name: 'b' },
{ name: 'aa' }
]);
console.log(
"getIntersectionOfDeeplyEqualDataStructures(set3, set4) ...",
getIntersectionOfDeeplyEqualDataStructures(set3, set4)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
function isDeepDataStructureEquality(a, b) {
let isEqual = Object.is(a, b);
if (!isEqual) {
if (Array.isArray(a) && Array.isArray(b)) {
isEqual = (a.length === b.length) && a.every(
(item, idx) => isDeepDataStructureEquality(item, b[idx])
);
} else if (
a && b
&& (typeof a === 'object')
&& (typeof b === 'object')
) {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
isEqual = (aKeys.length === bKeys.length) && aKeys.every(
(key, idx) => isDeepDataStructureEquality(a[key], b[key])
);
}
}
return isEqual;
}
</script>
Edit
As for Titus' approach ...
set1.forEach(value => {
if (
![...set2].some(o =>
Object.entries(o).every(([k, v], _, arr) =>
(Object.keys(value).length === arr.length && value[k] === v)
)
)
) {
set1.delete(value);
}
});
... which works for flat objects only, though already agnostic to key insertion order, one could optimize the code by ...
... not creating the keys array of the most outer currently processed object again and again with every nested some and every iteration.
thus, something like ... const valueKeys = Object.keys(value); ... before the if clause, already helps improving the code.
... inverting the nested some and every logic which does result in a more efficient way of ... deleting every flat data-item from the processed set which does not equal any flat data-item from the secondary set.
On top of that, one could implement a function statement which not only helps code-reuse but also makes the implementation independent from outer scope references.
For instance, the primary set which is operated and going to be mutated can be accessed as such a function's third parameter. But most important for outer scope independency is the also available thisArg binding for any set's forEach method. Thus any function statement or function expression can access e.g. the other/secondary set via this in case the latter was passed as the forEach's 2nd parameter.
Also an improved wording supports a better readability of the code ...
//the function naming of cause is exaggerated.
function deleteItemFromSourceWhichDoesNotEqualAnyItemFromBoundTarget(sourceItem, _, sourceSet) {
const targetSet = this;
const sourceKeys = Object.keys(sourceItem);
if (
// ... for any data-item from the (bound) target-set ...
[...targetSet].every(targetItem =>
// ... which does not equal the currently processed data-item from the source-set ...
Object.entries(targetItem).some(([targetKey, targetValue], _, targetEntries) =>
sourceKeys.length !== targetEntries.length || sourceItem[targetKey] !== targetValue
)
)
) {
// ... delete the currently processed data-item from the source-set.
sourceSet.delete(sourceItem);
}
}
const set1 = new Set([
{ name: 'a' }, // - to be kept.
{ name: 'b', lastname: 'bb' }, // - to be kept.
{ name: 'c' }, // - to be deleted.
{ name: 'd', nested: { name: 'a' } }, // - to be kept, but fails ...
]); // ... due to not being flat.
const set2 = new Set([
{ name: 'd', nested: { name: 'a' } }, // - should equal, but doesn't.
{ name: 'a' }, // - does equal.
{ lastname: 'bb', name: 'b' }, // - does equal.
{ name: 'e' }, // - doesn't equal.
]);
// `set1` is going to be mutated.
set1.forEach(deleteItemFromSourceWhichDoesNotEqualAnyItemFromBoundTarget, set2);
console.log(
'mutated `set1` now (almost) being equal to the intersection of initial `set1` and `set2` ...',
[...set1]
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
const set1 = new Set([
{name: 'a'},
{name: 'b', lastname: 'bb'},
{name: 'c'},
{name: 'd'}
]);
const set2 = new Set([
{name: 'b'},
{name: 'd'}
]);
const names = [...set2].map(s2 => s2.name);
console.log([...set1].filter(item => names.includes(item.name)));
const set1 = new Set([
{name: 'a'},
{name: 'b', lastname: 'bb'},
{name: 'c'},
{name: 'd'},
{name: 'e'}
]);
const set2 = new Set([
{name: 'c', lastname: 'ccc'},
{name: 'd'},
{name: 'b', lastname: 'cc'},
{name: 'e'}
]);
console.log([...set1].filter(item => {
const s2Arr = [...set2];
const itemKeys = Object.keys(item);
for(let i = 0; i < s2Arr.length; i++){
const s2Obj = s2Arr[i];
const s2ObjKeys = Object.keys(s2Obj);
if(s2ObjKeys.length == itemKeys.length){
let oneSame = true;
for(let j = 0; j < s2ObjKeys.length; j++){
const s2ObjKey = s2ObjKeys[j];
if(item[s2ObjKey] != s2Obj[s2ObjKey]){
oneSame = false;
}
}
if(oneSame)
return true;
}
}
return false;
}));
How to check if array contains different values with React.js and typescript?
Example:
[{
name: 'John',
value: 1,
}, {
name: 'John',
value: 1,
}, {
name: 'Carla',
value: 15,
}]
I want to return false if all objects in array are same, and true if there is at least one different object.
You can't use a direct equality comparison since objects will never return equal.
Ie {} != {}, and {name: 'John', value: 1} != {name: 'John', value: 1}.
So firstly you have to decide what you're going to define as 'equal' for these objects.
Let's say for the sake of this that you use just the name field as the test for equality. So if two objects in the array have the same name field, then you'll call them equal. Then you'd define the function:
type NameValue = {name: string, value: string}
const areEqual = (obj1: NameValue, obj2: NameValue): boolean => obj1.name === obj2.name
Of course you can change this function to reflect whatever you define as 'equal'. There are npm packages to help you with deep equality checks too, or you can JSON.stringify both and check that equality
Then you can use Array.some(). Array.some() will return true if any element in the array passes a test. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
Testing if any element is not equal to the first should be sufficient.
const areNotAllEqual = yourArray.some((currentElement) => {
return !areEqual(currentElement, yourArray[0])
})
After having commented on and criticized especially the approaches based on JSON.stringify, I want to contribute something on that matter. Since meanwhile all modern JS engines seem to be aware of an object's key order (in how this object was created) and also seem to guarantee such an order for key-iteration one could write a recursive function, which for any deeply nested but JSON-conform JS-objects reestablishes a normalized key-order for such objects but leaves arrays untouched.
Passing such key-normalized objects to JSON.stringify then makes such objects comparable by their's stringified signature ...
function defaultCompare(a, b) {
return ((a < b) && -1) || ((a > b) && 1) || 0;
}
function comparePropertyNames(a, b) {
return a.localeCompare
? a.localeCompare(b)
: defaultCompare(a, b);
}
function getJsonDataWithNormalizedKeyOrder(data) {
let value;
if (Array.isArray(data)) {
value = data.map(getJsonDataWithNormalizedKeyOrder);
} else if (data && (typeof data === 'object')) {
value = Object
.getOwnPropertyNames(data)
.sort(comparePropertyNames)
.reduce((obj, key) => {
obj[key] = getJsonDataWithNormalizedKeyOrder(data[key])
return obj;
}, {});
} else {
value = data;
}
return value;
}
const objA = {
name: 'foo',
value: 1,
obj: {
z: 'z',
y: 'y',
a: {
name: 'bar',
value: 2,
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
name: 'baz',
value: 3,
obj: {
k: 'k',
i: 'i',
c: 'c',
},
arr: ['5', 6, 'B', 'A'],
}],
},
},
arr: ['Z', 'Y', 1, '2'],
};
const objB = {
arr: ['Z', 'Y', 1, '2'],
obj: {
z: 'z',
y: 'y',
a: {
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
obj: {
k: 'k',
i: 'i',
c: 'c',
},
name: 'baz',
value: 3,
arr: ['5', 6, 'B', 'A'],
}],
name: 'bar',
value: 2,
},
},
name: 'foo',
value: 1,
};
const objC = {
arr: ['Z', 'Y', 1, '2'],
obj: {
z: 'z',
y: 'y',
a: {
obj: {
x: 'x',
w: 'w',
b: 'b',
},
arr: ['3', 4, 'W', 'X', {
obj: {
k: 'k',
i: 'i',
c: 'c',
},
name: 'baz',
value: 3,
arr: ['5', 6, 'B', 'A'],
}],
name: 'bar',
value: 2,
},
},
name: 'foo',
value: 2,
};
console.log(
'getJsonDataWithNormalizedKeyOrder(objA) ...',
getJsonDataWithNormalizedKeyOrder(objA)
);
console.log(
'getJsonDataWithNormalizedKeyOrder(objB) ...',
getJsonDataWithNormalizedKeyOrder(objB)
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)) ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA))
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)) ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB))
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)) ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC))
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)).length ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)).length
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)).length ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)).length
);
console.log(
'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)).length ...',
JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)).length
);
console.log(`
JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objA)
) === JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objB)
) ?`,
JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objA)
) === JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objB)
)
);
console.log(`
JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objA)
) === JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objC)
) ?`,
JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objA)
) === JSON.stringify(
getJsonDataWithNormalizedKeyOrder(objC)
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Applying the above to an approach which solves the OP's original problem in a more generic way then might look similar to the next provided lines ...
function defaultCompare(a, b) {
return ((a < b) && -1) || ((a > b) && 1) || 0;
}
function comparePropertyNames(a, b) {
return a.localeCompare
? a.localeCompare(b)
: defaultCompare(a, b);
}
function getJsonDataWithNormalizedKeyOrder(data) {
let value;
if (Array.isArray(data)) {
value = data.map(getJsonDataWithNormalizedKeyOrder);
} else if (data && (typeof data === 'object')) {
value = Object
.getOwnPropertyNames(data)
.sort(comparePropertyNames)
.reduce((obj, key) => {
obj[key] = getJsonDataWithNormalizedKeyOrder(data[key])
return obj;
}, {});
} else {
value = data;
}
return value;
}
const sampleList = [{
name: 'John',
value: 1,
}, {
value: 1,
name: 'John',
}, {
name: 'Carla',
value: 15,
}];
function hasDifferentValues(arr) {
// stringified first item reference.
const referenceItem = JSON.stringify(getJsonDataWithNormalizedKeyOrder(arr[0]));
// run `some` from a sub-array which excludes the original array's first item.
return arr.slice(1).some(item =>
referenceItem !== JSON.stringify(getJsonDataWithNormalizedKeyOrder(item))
);
}
console.log(
'hasDifferentValues(sampleList) ?',
hasDifferentValues(sampleList)
);
console.log(
'hasDifferentValues(sampleList.slice(0,2)) ?',
hasDifferentValues(sampleList.slice(0,2))
);
console.log(
'hasDifferentValues(sampleList.slice(0,1)) ?',
hasDifferentValues(sampleList.slice(0,1))
);
console.log(
'hasDifferentValues(sampleList.slice(1)) ?',
hasDifferentValues(sampleList.slice(1))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
I'd check whether stringified object array includes stringified item by referencing to a copied array where I remove the latest item. I'll use Array.every() to compare if all the items match together and then return the opposite value.
However, this can be very heavy operation if an object array is very lengthy
const arrSame = [{name: 1}, {name: 1}, {name: 1}];
const arrDiff = [{name:1}, {name: 2}, {name: 2}];
const arrDiff2 = [{name:1}, {name: 1}, {name: 2}];
const hasDifferentValues = (arr) => !arr.every((item, i, ref) => JSON.stringify([...ref].shift()).includes(JSON.stringify(item)));
console.log(hasDifferentValues(arrSame));
console.log(hasDifferentValues(arrDiff));
console.log(hasDifferentValues(arrDiff2));
This is not exactly react specific, but to check for differences you can iterate through the array using every like so.
const fooArray = [{
name: 'John',
value: 1,
nest: {
isValid: [1, 2]
}
},
{
value: 1,
name: 'John',
nest: {
isValid: [1, 1]
}
}, {
name: 'John',
value: 1,
nest: {
isValid: [1, 1]
}
}
]
// check each member against the last, see if there is a diff
const isSame = (element, index, arr) => {
if (index > 0) {
// https://stackoverflow.com/questions/1068834/object-comparison-in-javascript
// return JSON.stringify(element) === JSON.stringify(arr[index - 1])
// alternatively, you can check to see if some of the values are different
// by stringifying and checking if either are permuations of each other
// this is probably not the ideal way, but I added it for the sake of a different solution
const currentObStr = JSON.stringify(element).split("").sort().join()
const prevObStr = JSON.stringify(arr[index - 1]).split("").sort().join()
return currentObStr === prevObStr
}
return true
}
const everyElementIsSame = fooArray.every(isSame)
console.log(everyElementIsSame)
How would you transform codes into result using lodash ?
const codes = [
{a: 'aa', b: [ 8518 ], c: [ '2146' ]},
{a: 'bb', b: [ 120123 ], c: [ 'D835', 'DD3B' ]},
{a: 'cc', b: [ 168, 532 ], c: [ '00A8' ] }
]
const result = [
{a: 'aa', b:8518, c:'2146'},
{a: 'bb', b:120123, c:'D835'},
{a: 'bb', b:120123, c:'DD3B'},
{a: 'cc', b:168, c:'00A8'},
{a: 'cc', b:532, c:'00A8'}
]
Use nested Array.flatMap() calls (or lodash's _.flatMap()) to iterate the main array, and the b objects , and Array.map() to iterate the c arrays to create an array of objects with all the combinations of b and c values:
const codes = [{ a: 'aa', b: [8518], c: ['2146'] }, { a: 'bb', b: [120123], c: ['D835', 'DD3B'] }, { a: 'cc', b: [168, 532], c: ['00A8'] }]
const result = codes.flatMap(o =>
o.b.flatMap(b =>
o.c.map(c => ({ ...o, b, c }))
)
)
console.log(result)
With plain Javascript you could separate the problem into two task, one for build a cartesian product of an array with a nested structure and another for mapping the part result of the cartesian products.
getCartesian is a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian again and build new objects.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
var input = [{ a: 'aa', b: [8518], c: ['2146'] }, { a: 'bb', b: [120123], c: ['D835', 'DD3B'] }, { a: 'cc', b: [168, 532], c: ['00A8'] }],
cartesian = input.flatMap(o => getCartesian(o));
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I created a function to remove the properties I tell him to
function trimProperties(data, properties) {
return data.map(o => {
Object.keys(o).forEach(k => {
if (properties.includes(k)) {
delete o[k];
}
});
return o;
});
}
My use case is usually like this
let array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
]
// Remove every property 'b' or 'c' from the objects inside the array
trimProperties(array, ['b','c']);
My question is simple, how can I make this function faster, because my array sometimes can get pretty big since it's the result set from a database access
delete cause indexes recalculation all the time, creating new array would be faster
let array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
]
function trimProperties(data, properties) {
let i = 0;
const result = []
while (i < data.length) {
var o = {};
Object.keys(data[i]).forEach(k => {
if (!properties.includes(k)) {
o[k] = data[i][k];
}
})
i++;
if (Object.keys(o).length) {
result.push(o);
}
}
return result;
}
// Remove every property 'b' or 'c' from the objects inside the array
console.log(trimProperties(array, ['b','c']));
A one liner:
array.map(o => Object.fromEntries(Object.entries(o).filter(([k,v]) => !['b','c'].includes(k))))
Demo:
const array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
];
const excluded = ['b','c'];
const filtered = array.map(o => Object.fromEntries(Object.entries(o).filter(([k,v]) => !excluded.includes(k))));
console.log(filtered)
If I have an object, like so:
const test = [
{ x: 'A', y:'1' },
{ x: 'A', y:'2' },
{ x: 'B', y:'1' },
{ x: 'A', y:'3' },
{ x: 'C', y:'1' },
];
How can I go through it, and find the in order sequence [A, B, C] from x, where [A, B, C] belongs to a unique y?
So far I tried iterating through the object using a for loop, finding all 'A', 'B', 'C', in order, but I cannot ensure that they all belong to the same y item.
Transform the array into an object of arrays corresponding to only one particular y first:
const test = [
{ x: 'A', y:'1' },
{ x: 'A', y:'2' },
{ x: 'B', y:'1' },
{ x: 'A', y:'3' },
{ x: 'C', y:'1' },
];
const reducedToYs = test.reduce((accum, { x, y }) => {
accum[y] = (accum[y] || '') + x;
return accum;
}, {});
const found = Object.entries(reducedToYs)
.find(([y, str]) => str.includes('ABC'));
console.log('y: ' + found[0] + ', entire string: ' + found[1]);
Create a function that takes the target Y value. Loop through the test array and compare the y value to your target value and if it matches - push the x value into an array. Then return that array.
If a string is required ("ABC)" then rather than creating an array create a string and append the x value to it to build the string that is then returned.
const test = [
{ x: 'A', y:'1' },
{ x: 'A', y:'2' },
{ x: 'B', y:'1' },
{ x: 'A', y:'3' },
{ x: 'C', y:'1' },
];
function testValue(str) {
let xArray = [];
test.forEach(function(item) {
if(item['y'] === str) {xArray.push(item['x'])}
})
return xArray;
}
console.log(testValue('1')) // gives ["A", "B", "C"]