Is there a way to compare these 2 objects based on topicID and items->item->id and return true for being same? (it must ignore unique element)
const var1 = [
{
unique: "8123456",
topicID: "1234",
items: {
item: [
{
id: "x",
},
{
id: "y",
},
],
},
},
{
unique: "123456",
topicID: "123",
items: {
item: [
{
id: "b",
},
{
id: "a",
},
],
},
},
];
const var2 = [
{
unique: "3123456",
topicID: "123",
items: {
item: [
{
id: "a",
},
{
id: "b",
},
],
},
},
{
unique: "2123456",
topicID: "1234",
items: {
item: [
{
id: "y",
},
{
id: "x",
},
],
},
},
];
a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]
function comparer(otherArray){
return function(current){
return otherArray.filter(function(other){
return other.value == current.value && other.display == current.display
}).length == 0;
}
}
var onlyInA = a.filter(comparer(b));
var onlyInB = b.filter(comparer(a));
result = onlyInA.concat(onlyInB);
console.log(result);
Here is put your required data and use this code you will get success
Try using:
const var1 = [
{
unique: "8123456",
topicID: "1234",
items: {
item: [
{
id: "x",
},
{
id: "y",
},
],
},
},
{
unique: "123456",
topicID: "123",
items: {
item: [
{
id: "b",
},
{
id: "a",
},
],
},
},
];
const var2 = [
{
unique: "3123456",
topicID: "123",
items: {
item: [
{
id: "a",
},
{
id: "b",
},
],
},
},
{
unique: "2123456",
topicID: "1234",
items: {
item: [
{
id: "y",
},
{
id: "x",
},
],
},
},
];
const var3 = [
{
unique: "8123456",
topicID: "1234",
items: {
item: [
{
id: "x",
},
{
id: "y",
},
],
},
},
{
unique: "123456",
topicID: "123",
items: {
item: [
{
id: "b",
},
{
id: "a",
},
],
},
},
];
function objCompare(object1, object2) {
const keys1 = Object.keys(object1);
const keys2 = Object.keys(object2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
const val1 = object1[key];
const val2 = object2[key];
const isObj= checkObj(val1) && checkObj(val2);
if (
isObj && !objCompare(val1, val2) ||
!isObj && val1 !== val2
) {
return false;
}
}
return true;
}
function checkObj(object) {
return object != null && typeof object === 'object';
}
console.log(objCompare(var1,var2));
console.log(objCompare(var1,var3));
Hope this helps !!!
Without knowing the exact use case, I'll outline a general idea of how you could go about it.
For each item in the array, generate a key based on the topicID and the concatenation of the id within items. From there, you construct a set of both lots of keys, then compare them. This would work assuming that:
There are no duplicates in a single array.
You only need to test for "equality". If you need to pull out the duplicated items it's more difficult, but the same approach can be followed.
const constructKey = o =>
`${o.topicID}_${o.items.item.map(item => item.id).join('')}`
const setEq = (a, b) => a.size === b.size && [...a].every(v => b.has(v));
const var1Keys = new Set(var1.map(constructKey));
const var2Keys = new Set(var2.map(constructKey));
console.log(setEq(var1Keys, var2Keys))
EDIT: Based on your comment, it seems as though you want to compare items regardless of order. Something like this:
const constructMap = (arr) =>
arr.reduce(
(map, { topicID, items }) =>
map.set(topicID, new Set(items.item.map(({ id }) => id))),
new Map(),
)
const setEq = (a, b) => a.size === b.size && [...a].every((v) => b.has(v))
const mapEq = (a, b) =>
a.size === b.size &&
[...a.entries()].every(([k, v]) => b.has(k) && setEq(v, b.get(k)))
const var1Map = constructMap(var1)
const var2Map = constructMap(var2)
console.log(mapEq(var1Map, var2Map))
Related
I found here this code and works good. But I also need to know the "id" which is multible in use. e.g. in another array
var data = [
{"id":"1","Group":"Wohnzimmer","Light":"Diele", "type":"ct"},
{"id":"1","Group":"Wohnzimmer","Light":"Diele", "type":"ct"},
{"id":"2","Group":"Wohnzimmer","Light":"Diele", "type":"bri"},
{"id":"3","Group":"Wohnzimmer","Light":"Diele", "type":"color"},
{"id":"3","Group":"Wohnzimmer","Light":"Diele", "type":"color"},
]
var a = data.reduce((accumulator, current) => {
if (checkIfAlreadyExist(current)) {
return accumulator;
} else {
return [...accumulator, current];
}
function checkIfAlreadyExist(currentVal) {
return accumulator.some((item) => {
return (item.id === currentVal.id &&
item.Light === currentVal.Light &&
item.type === currentVal.type);
});
}
}, []);
console.log(a);
Reduced (it works fine!):
[{
Group: "Wohnzimmer",
id: "1",
Light: "Diele",
type: "ct"
}, {
Group: "Wohnzimmer",
id: "2",
Light: "Diele",
type: "bri"
}, {
Group: "Wohnzimmer",
id: "3",
Light: "Diele",
type: "color"
}]
Now, I need also the result of the deleted objects, like the following:
[{
Group: "Wohnzimmer",
id: "1",
Light: "Diele",
type: "ct"
},{
Group: "Wohnzimmer",
id: "3",
Light: "Diele",
type: "color"
}]
You can do this efficiently in linear time:
let key = obj => [obj.id, obj.Light, obj.type].join('##')
let seen = new Set,
unique = [],
removed = []
for (let obj of data) {
let k = key(obj);
(seen.has(k) ? removed : unique).push(obj)
seen.add(k)
}
use array.prototype.map and array.prototype.some
var values = [
{ name: 'someName1' },
{ name: 'someName2' },
{ name: 'someName4' },
{ name: 'someName2' }
];
var valueArr = values.map(function(item){ return item.name });
var isDuplicate = valueArr.some(function(item, idx){
return valueArr.indexOf(item) != idx
});
console.log(isDuplicate);
Using you current logic you could archive your preferred output with small changes, use a object instead with two arrays instead.
var data = [
{ id: "1", Group: "Wohnzimmer", Light: "Diele", type: "ct" },
{ id: "1", Group: "Wohnzimmer", Light: "Diele", type: "ct" },
{ id: "2", Group: "Wohnzimmer", Light: "Diele", type: "bri" },
{ id: "3", Group: "Wohnzimmer", Light: "Diele", type: "color" },
{ id: "3", Group: "Wohnzimmer", Light: "Diele", type: "color" },
];
var { unique, removed } = data.reduce(
(accumulator, current) => {
if (checkIfAlreadyExist(current)) {
return {
...accumulator,
removed: [...accumulator.removed, current],
};
} else {
return {
...accumulator,
unique: [...accumulator.unique, current],
};
}
function checkIfAlreadyExist(currentVal) {
return accumulator.unique.some((item) => {
return (
item.id === currentVal.id &&
item.Light === currentVal.Light &&
item.type === currentVal.type
);
});
}
},
{
unique: [],
removed: [],
}
);
console.log("Unique");
console.log(unique);
console.log("Removed");
console.log(removed);
Just create another array to store deleted items and if checkIfAlreadyExist returns true push current into the array.
var data = [
{"id":"1","Group":"Wohnzimmer","Light":"Diele", "type":"ct"},
{"id":"1","Group":"Wohnzimmer","Light":"Diele", "type":"ct"},
{"id":"2","Group":"Wohnzimmer","Light":"Diele", "type":"bri"},
{"id":"3","Group":"Wohnzimmer","Light":"Diele", "type":"color"},
{"id":"3","Group":"Wohnzimmer","Light":"Diele", "type":"color"},
]
var deleted = []
var a = data.reduce((accumulator, current) => {
if (checkIfAlreadyExist(current)) {
deleted.push(current)
return accumulator;
} else {
return [...accumulator, current];
}
function checkIfAlreadyExist(currentVal) {
return accumulator.some((item) => {
return (item.id === currentVal.id &&
item.Light === currentVal.Light &&
item.type === currentVal.type);
});
}
}, []);
console.log(a);
console.log(deleted)
I have the reducer that contains some of the list objects.
const list = [
{
name: 'A',
products: { items: [] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
]
I want to add new items to the product key.
reducer
export const addProductToSubscription = (state, { name, products }) => ({
...state,
list: state.list.map((v) =>
name === v.subscriptionName ? [...v.products, { ...v.products, items: products }] : v
),
})
disptach like this,
dispatch("A",[{qty:2}])
expected output
const list = [
{
name: 'A',
products: { items: [{ qty: 2 }] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
]
What reducer not updating the state.
Thanks!!
I've recreated your environment and end up like-
const state = {
list: [
{
name: "A",
products: { items: [] },
},
{
name: "B",
products: { items: [{ qty: 1 }] },
},
],
};
const updateState = (state, { name, products }) => {
return {
...state,
list: state.list.map(v => {
return {
...v,
products: {
...v.products,
items: [
...v.products.items,
...products
]
}
}
}),
};
};
const res = updateState(state, { name: "A", products: [{ qty: 2 }, {qty: 4}] });
console.log(JSON.stringify(res));
.as-console-wrapper{min-height: 100%!important; top: 0}
A more advanced solution than Object.assign and spread operator(...) - immutability-helper
const update = require('immutability-helper');
const assert = require('assert');
const list = [
{
name: 'A',
products: { items: [] },
},
{
name: 'B',
products: { items: [{ qty: 1 }] },
},
];
function addProductToSubscription(state = list, { name, products }) {
return update(state, {
$apply: (self) => {
return self.map((v) => {
if (v.name === name) {
return update(v, { products: { items: { $push: products } } });
}
return v;
});
},
});
}
const actual = addProductToSubscription(undefined, { name: 'A', products: [{ qty: 2 }] });
console.log(JSON.stringify(actual, null, 2));
assert(actual !== list, 'new copy');
assert(actual[0] !== list[0], 'new copy for A object');
assert(actual[0].products !== list[0].products, 'new copy for A object products');
assert(actual[0].products.items !== list[0].products.items, 'new copy for A object products items');
Output:
[
{
"name": "A",
"products": {
"items": [
{
"qty": 2
}
]
}
},
{
"name": "B",
"products": {
"items": [
{
"qty": 1
}
]
}
}
]
Take the new copy using spread operator and update to the state
export const addProductToSubscription = (state, { name, products }) => ({
...state,
list: state.list.map((v) =>
v.name === name
? {
...v,
products: { items: [...v.products.items, ...products] },
}
: v
),
});
I have the following:
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
]
What I want to achieve is to have an array with each company -> modelName combination.
So it should look like :
[{
value: 'sunafga',
label: 'Sunafga',
children: [{
value: 'atoga3',
label: 'Atoga3'
},
{
value: 'bisuda-x23',
label: 'bisuda-X23'
},
{
value: 'oidas',
label: 'Oidas'
},
{
value: 'zarusa-m3',
label: 'Zarusa-M3'
},
{
value: 'valasi-W',
label: 'Kalasi-W'
}
]
},
{
value: 'kemaite',
label: 'Kemaite',
children: [{
value: 'bisuda-x23',
label: 'bisuda-X23'
},
{
value: 'oidas',
label: 'Oidas'
},
]
},
]
you probably want a two step transform here, one to a useful structure to remove all those dups, then just nudge that into your desired structure
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
]
// transform to a useful structure for removing duplicates
const companyMap = itemsArr.reduce((acc, val) => {
val.baseDetails.companies.forEach(c => {
acc[c] = val.baseDetails.modelNames.reduce((a, m) => Object.assign(a, {[m]: true}), (acc[c] || {}))
});
return acc
}, {})
// transform your useful structure to the desired one
const newArray = Object.entries(companyMap).map(([company, models]) => {
return {
value: company.toLowerCase(),
label: company,
children: Object.keys(models).map(model => ({label: model, value: model.toLowerCase()}))
}
})
console.log(newArray)
you could use this if you want as your intermediary transform if you want to reduce all the way down:
const companyMap = itemsArr.reduce((cMap, item) =>
Object.assign(cMap,
item.baseDetails.companies.reduce((iMap, c) =>
Object.assign(iMap,
{[c]: item.baseDetails.modelNames.reduce((a, m) => Object.assign(a, {[m]: true}), (cMap[c] || {}))}
)
, {})
)
, {})
Here's a solution if using reduce isn't mandatory:
const itemsArr = [{
id: 0,
baseDetails: {
modelNames: ["Atoga3"],
companies: ['Sunafga']
}
},
{
id: 1,
baseDetails: {
modelNames: ["Bisuda-X23", "Oidas"],
companies: ["Sunafga", "Kemaite"]
}
},
{
id: 2,
baseDetails: {
modelNames: ["Zarusa-M3", "Kalasi-W"],
companies: ["Abado", "Sunafga"]
}
}
];
const result = [];
itemsArr.forEach(item => {
item.baseDetails.companies.forEach(company => {
let companyEntry = result.find(resultEntry => resultEntry.label === company);
if (!companyEntry) {
companyEntry = {
label: company,
value: company.toLowerCase(),
children: []
};
result.push(companyEntry);
}
const companyChildren = companyEntry.children;
item.baseDetails.modelNames.forEach(modelName => {
if (!companyChildren.find(companyModel => companyModel.label === modelName)) {
companyChildren.push({
label: modelName,
value: modelName.toLowerCase()
});
}
});
});
});
console.log(result);
I have the following data stored in a variable:
let categories = [
{
name: "a",
nodes: [
{
name: "aa",
nodes: [
{
name: "aaa"
}
]
},
{
name: "ab",
},
{
name: "ac",
},
{
name: "ad",
}
]
},
{
name: "b",
nodes: [
{
name: "ba",
},
{
name: "bb",
},
{
name: "bc",
},
{
name: "bd",
}
]
}
];
And I have the following recursive function which accepts the categories variable and name.
function getCategoryParents(categories, name) {
for (let index = 0; index < categories.length; index++) {
const category = categories[index];
if (category.name === name) {
}
if (category.nodes && category.nodes.length) {
category.nodes.forEach(cat => this.getCategoryParents([cat], name));
}
}
}
I want to return an array of names containing the name in the parameter and the parents of that name.
For example if I called getCategoryParents(categories, "aaa") it should returns ["a", "aa", "aaa"]. because aa is the parent of aaa and a is the parent of aa.
I hope it's clear.
I tweaked your function so it would actually return some values when it finds the matches :
function getCategoryParents(arr, name) {
for (let child of arr) {
if (child.name === name) {
return name;
} else if (child.nodes.length > 0) {
var x = getCategoryParents(child.nodes, name);
if (x) return Array.isArray(x) ? [child.name, ...x] : [child.name, x];
}
}
}
let categories = [
{
name: "a",
nodes: [
{
name: "aa",
nodes: [
{
name: "aaa"
}
]
},
{
name: "ab"
},
{
name: "ac"
},
{
name: "ad"
}
]
},
{
name: "b",
nodes: [
{
name: "ba"
},
{
name: "bb"
},
{
name: "bc"
},
{
name: "bd"
}
]
}
];
const result = getCategoryParents(categories, "aaa");
console.log(result); // ["a", "aa", "aaa"]
arr1 = [
{
name: "will",
value: "1"
},
{
name: "nelson",
value: "3"
}
];
and
arr2 = [
{
name: "will",
value: 1,
submenu: [
{
name: "ralph",
value: 2
}
]
}
]
then remove ralph from the second array. i already created a function who do it but just check the first element and not verify the submenu.
comparador(arrSecundario) {
return (arrAtual) => {
return arrSecundario.filter(function (other) {
return other.value === arrAtual.value;
}).length !== 0;
};
}
this.arr2.filter(this.comparador(this.arr1));
Need to map array after filter. You can do like this and can also add "prop === 'submenu'" for specifically checking submenu inner array only.
var arr1 = [
{
name: "will",
value: "1"
},
{
name: "nelson",
value: "3"
}
];
var arr2 = [
{
name: "will",
value: 1,
submenu: [
{
name: "ralph",
value: 2
},
// {
// name: "nelson",
// value: 3
// }
]
}
];
function filterComparador(arrSecundario) {
return (arrAtual) => {
return arrSecundario.filter((other) => {
return other.value == arrAtual.value;
}).length != 0;
};
}
function mapComparador(arrSecundario) {
return (arrAtual) => {
Object.keys(arrAtual).forEach((prop) => {
if (Array.isArray(arrAtual[prop])) {
let propValue = arrAtual[prop].filter(this.filterComparador(arrSecundario));
if (propValue.length > 0) {
arrAtual[prop] = propValue.map(this.mapComparador(this.arrSecundario));
} else {
delete arrAtual[prop];
}
}
});
return arrAtual;
};
}
var manipulatedArray = this.arr2.filter(this.filterComparador(this.arr1))
.map(this.mapComparador(this.arr1));
console.log(manipulatedArray);