Split an object in to array of objects based on similar values - javascript

var pr = {
name: "ball",
race: "ball",
weapon: "axe",
};
var save=new Object;
var keys=Object.keys(pr);
for(var k in pr) {
}
console.log(save); // should end up with {name:'ball',race:'ball'}

If I have understood the question correctly, one option is:
const keys = Object.keys(pr);
const ret = keys.reduce((ret, k, i) => {
const f = keys.find((k2, i2) => i !== i2 && pr[k] === pr[k2]);
if (f) ret[k] = pr[k];
return ret;
}, {});

Here is what I came up with.
var pr = {
name: "ball",
race: "ball",
weapon: "axe"
};
const dupValues = Object.values(pr).reduce(
(acc, cur) => ({ ...acc, [cur]: (acc[cur] || 0) + 1 }),
{}
);
const result = Object.keys(pr)
.filter(key => dupValues[pr[key]] > 1)
.reduce((acc, curr) => ({ ...acc, [curr]: pr[curr] }), {});
console.log(result);
// {name:'ball',race:'ball'}

One way to do it is use the save object as a histogram, keeping track of duplicates. Then, filter out any keys with 0 count using reduce. This should have better performance than a linear function like find:
var pr = {
name: "ball",
race: "ball",
weapon: "axe"
};
var save = {};
for (var k in pr) {
save[pr[k]] = pr[k] in save ? save[pr[k]] + 1 : 0;
}
var result = Object.keys(pr).reduce((a, e) => {
if (save[pr[e]]) { a[e] = pr[e]; }
return a;
}, {});
console.log(result);

It works. Simple and clear. References : Array.reduce()
Iterate through each key value pair, and accumulate the result until the loop ends.
var pr = {
name: "ball",
race: "ball",
weapon: "axe",
item:"bat",
newitem:"bat",
newweapon: "axe"
};
var result = Object.keys(pr).reduce(function(acc, key){
var ispresent = false;
acc.forEach(function(obj,i){
if(ispresent) return;
if(Object.values(obj)[0]===pr[key])
{
obj[key]=pr[key];
ispresent = true;
}
});
if(!ispresent)
{
var newobj = {};newobj[key]=pr[key];
acc.push(newobj)
}
return acc;
},[])
console.log(result)

Related

JavaScript: Create object with nested properties from string split by specific character

How to use the name property in this object:
const obj = {
name: 'root/branch/subbranch/leaf',
value: 'my-value'
}
To create an object with the following format:
{
root: {
branch: {
subbranch: {
leaf: 'my-value'
}
}
}
}
You could do this using split and reduce
const obj = {
name: 'root/branch/subbranch/leaf',
value: 'my-value'
}
let newObj = {}
const parts = obj.name.split('/')
parts.reduce((prev, curr, i) => (
Object.assign(
prev,
{[curr]: i === parts.length - 1 ? obj.value : Object(prev[curr])}
),
prev[curr]
), newObj)
console.log(newObj)
I wrote a reciursive function and a wrapper to call it.
const obj = {
name: 'root/branch/subbranch/leaf',
value: 'my-value'
}
const recursiveNest = (result, value, arr, index = 0) => {
const path = arr[index]
if (index < arr.length - 1) {
result[path] = {}
index +=1;
recursiveNest(result[path], value, arr, index)
} else {
result[arr[index]] = value;
}
};
const createNestedObject = (obj, splitBy) => {
let result = {}
recursiveNest(result, obj.value, obj.name.split(splitBy))
return result;
}
console.log(createNestedObject(obj, '/'));
Lodash provides setWith(object, path, value, [customizer]):
const obj = {
name: 'root/branch/subbranch/leaf',
value: 'my-value'
}
console.log(_.setWith({}, obj.name.split('/'), obj.value, _.stubObject))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>

Mark only second duplicated object in js array

I have a list of objects:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}]
I use the below methods to get duplicated objects(by name) and assign a prop isDuplicated:
const duplicatedNames = arrayOfObjects
.map(e => e['name'])
.map((e, i, final) => final.indexOf(e) !== i && i++)
.filter(obj => arrayOfObjects[obj])
.map(e => !arrayOfObjects[e]['name']);
const result = arrayOfObjects.filter((obj, i) => {
return duplicatedNames.includes(obj.name) && Object.assign(obj, { isDuplicated: true });
});
I receive an array like:
[{name: 'Elza', isDuplicated: true}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
I would like to mark only the second occurrence of duplicate- so i would like the result to be:
[{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza', isDuplicated: true}]
Can anyone know how to do it base on my code?
Here is a function that checks if a name exist more then once.
let data = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}, {name: "Jerry"}, {name: "Jerry"}];
function checkDup(arr){
let cache = [];
return arr.map(({name}, index) => {
if(!cache.find(el => el.name == name)){
cache.push({name, index});
return {name, index};
}
let { index: cacheIndex } = cache.find(el => el.name === name);
return {name,index: cacheIndex , isDuplicated: true};
})
}
console.log(checkDup(data));
You could create a Set of names. If the size of the set is same as after the name has been added, then it's duplicate record.
const input = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}],
names = new Set;
for (const o of input)
if (names.size === names.add(o.name).size)
o.isDuplicate = true
console.log(input)
You can try this:
let users = [{name:'Elza'}, {name:'Tom'}, {name:'Elza'}]
let flags = [], output = [];
users.forEach(user => {
if (flags[user.name]) {
output.forEach(item => {
if (item.name === user.name) {
item.isDuplicated = true
output.push(user);
}
})
} else {
flags[user.name] = true;
output.push(user);
}
})
Given your original array A, you could create a temporary array B and, for each a element of A, check:
if B contains a.name, then set a.isDuplicated to true;
else, push a.name in B.
let A = [{name: 'Elza'}, {name: 'Tom'}, {name: 'Elza'}];
let B = [];
A.forEach(a => {
if (B.includes(a.name)) {
a.isDuplicated = true;
} else {
B.push(a.name);
}
});
console.log(A);
You can use reduce with a helper object:
const collection = [{ name: 'Elza'}, { name: 'Tom'}, { name: 'Elza' }]
const helper = {}
const result = collection.reduce((acc, { name }) => {
if (helper[name]) {
return [...acc, { name, isDuplicate: true }]
}
helper[name] = 'x';
return [...acc, { name }]
}, [])
console.log(result)

Transform an object to add new keys based on existing key-values

I need to transform this object :
myObject = {
"pageName": "home",
"dataExtract": "data1|data2=value2|data3=value3|data4=value4a,value4b,value4c"}
To this one:
myObject_mod = {
'pageName' : 'home',
'dataExtract' : {
'data1' : '', //no value for 'data1'
'data2' : 'value2',
'data3' : 'value3',
'data4' : {
'data4key1' : 'value4a',
'data4key2' : 'value4b',
'data4key3' : 'value4c'
}
}
I've started by taking the 'dataExtract' key, and split it by "|", so I get its values splited:
myObject.dataExtract.split("|");
(4) ["data1", "data2=value2", "data3=value3", "data4=value4a,value4b,value4c"]
How can I continue?
Use reduce to build up your result object for every entry in your data extract. The general form would be:
myArray.reduce((resultObject, entryString) => {
// some logic here
resultObject[key] = resultValue;
return resultObject
}, {});
For example:
array = {
"pageName": "home",
"dataExtract": "data1|data2=value2|data3=value3|data4=value4a,value4b,value4c"
};
array_mod = {
pageName: array.pageName,
dataExtract: array.dataExtract.split("|").reduce((obj, entry) => {
// handle cases like data1
if (entry.indexOf('=') === -1) {
obj[entry] = '';
return obj;
}
// handle cases like data2 and data3
const [key, value] = entry.split('=', 2);
if (value.indexOf(',') === -1) {
obj[key] = value;
return obj;
}
// handle cases like data4
const values = value.split(',');
obj[key] = values.reduce((o, v, i) => (o[`${key}key${i+1}`] = v, o), {});
return obj;
}, {})
};
console.log(array_mod);
Use a combination of Array.split(), Array.reduce(), and destructuring, to break the string into keys and values, and rebuild as an object:
const object = {
"pageName": "home",
"dataExtract": "data1|data2=value2|data3=value3|data4=value4a,value4b,value4c"
}
const result = {
...object,
dataExtract: object.dataExtract.split('|')
.reduce((r, kv) => {
const [key, value = ''] = kv.split('=')
r[key] = !value.includes(',') ?
value
:
value.split(',').reduce((ra, val, i) => {
ra[`${key}key${i + 1}`] = val;
return ra;
}, {})
return r
}, {})
}
console.log(result)
An alternative to what was already posted, also using String.split and Array.reduce:
const array = {
"pageName": "home",
"dataExtract": "data1|data2=value2|data3=value3|data4=value4a,value4b,value4c"
};
const array_mod = {
pageName: array.pageName,
dataExtract: array.dataExtract.split('|').reduce((r, cur) => {
const [k, v = ''] = cur.split('=', 2);
const vs = v.split(',');
r[k] = vs.length > 1 ? vs.reduce((sr, scur, i) => (sr[`${k}key${i + 1}`] = scur, sr), {}) : v;
return r;
}, {})
};
console.log(array_mod);
With comments and more explicit variable names:
const array = {
"pageName": "home",
"dataExtract": "data1|data2=value2|data3=value3|data4=value4a,value4b,value4c"
};
const array_mod = {
pageName: array.pageName,
// Split by | and build a key => value object from it
dataExtract: array.dataExtract.split('|').reduce((data, entry) => {
// Grab key (before `=`) and value (after `=`)
const [key, value = ''] = entry.split('=', 2);
// Grab subvalues (separated by `,`) if any
const subValues = value.split(',');
// If there are at least 2 subvalues, build a key => value object from them
data[key] = subValues.length > 1
? subValues.reduce((sub, subVal, i) => (sub[`${key}key${i + 1}`] = subVal, sub), {})
// Otherwise return the value as string
: value;
return data;
}, {})
};
console.log(array_mod);

Add values of elements in array using javascript with out using const

I had an array with
0:{Name: "Test1",Cost:100,Revenue:200}
1:{Name: "Test2",Cost:100,Revenue:100}
2:{Name: "Test3",Cost:100,Revenue:300}
3:{Name: "Test2",Cost:200,Revenue:100}
4:{Name: "Test1",Cost:100,Revenue:300}
5:{Name: "Test4",Cost:100,Revenue:300}
I am expecting result with out duplicates based on names and other values (cost and revenue) as added
0:{Name: "Test1",Cost:200,Revenue:500}
1:{Name: "Test2",Cost:300,Revenue:200}
2:{Name: "Test3",Cost:100,Revenue:300}
3:{Name: "Test4",Cost:100,Revenue:300}
I am trying with below code
var removeDuplicates = function(originalArray, prop) {
var newArray = [];
var lookupObject = {};
for(var i in originalArray) {
lookupObject[originalArray[i][prop]] = originalArray[i];
}
for(i in lookupObject) {
newArray.push(lookupObject[i]);
}
return newArray;
}
console.log('Name array ',removeDuplicates(tempRoleMap, 'Name'));
Can you help me out
You can use reduce to iterate over the array while assigning to an accumulator object indexed by Name. On each array item, either assign it as the new object at that key in the accumulator if it doesn't exist yet, or iterate over the item's entries (other than Name) and add to the appropriate property in the accumulator.
At the end, you'll have an object indexed by Names, so to get the array out of the object, call Object.values on it:
const arr=[{Name:"Test1",Cost:100,Revenue:200},{Name:"Test2",Cost:100,Revenue:100},{Name:"Test3",Cost:100,Revenue:300},{Name:"Test2",Cost:200,Revenue:100},{Name:"Test1",Cost:100,Revenue:300},{Name:"Test4",Cost:100,Revenue:300}]
const result = Object.values(arr.reduce((a, { Name, ...rest }) => {
if (!a[Name]) a[Name] = { Name, ...rest };
else {
Object.entries(rest).forEach(([key, val]) => {
a[Name][key] += val;
});
}
return a;
}, {}));
console.log(result);
It's best to use ES6+ when writing code, and then you can transpile it down to ES5 automatically with Babel and polyfills. But, if you had to write in ES5, then:
var arr=[{Name:"Test1",Cost:100,Revenue:200},{Name:"Test2",Cost:100,Revenue:100},{Name:"Test3",Cost:100,Revenue:300},{Name:"Test2",Cost:200,Revenue:100},{Name:"Test1",Cost:100,Revenue:300},{Name:"Test4",Cost:100,Revenue:300}]
var obj = arr.reduce(function(a, item) {
var Name = item.Name;
if (!a[Name]) a[Name] = item;
else {
Object.keys(item).forEach(function(key) {
if (key === 'Name') return;
a[Name][key] += item[key];
});
}
return a;
}, {});
var output = [];
Object.keys(obj).forEach(function(key) {
output.push(obj[key]);
});
console.log(output);
As you can see, it's a whole lot wordier and inelegant - better to write in the latest and greatest version of the language, and transpile down to your target environment automatically later.
You can get the desired output using .reduce() and Object.values():
let data = [
{Name: "Test1", Cost:100, Revenue:200},
{Name: "Test2", Cost:100, Revenue:100},
{Name: "Test3", Cost:100, Revenue:300},
{Name: "Test2", Cost:200, Revenue:100},
{Name: "Test1", Cost:100, Revenue:300},
{Name: "Test4", Cost:100, Revenue:300}
];
let result = Object.values(
data.reduce((r, c) => {
r[c.Name] = r[c.Name] || {};
r[c.Name].Cost = (r[c.Name].Cost || 0) + c.Cost;
r[c.Name].Revenue = (r[c.Name].Revenue || 0) + c.Revenue;
return r;
}, {})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You will find a solution in the snippet below:
var arr = [{Name: "Test1",Cost:100,Revenue:200},
{Name: "Test2",Cost:100,Revenue:100},
{Name: "Test3",Cost:100,Revenue:300},
{Name: "Test2",Cost:200,Revenue:100},
{Name: "Test1",Cost:100,Revenue:300},
{Name: "Test4",Cost:100,Revenue:300}];
function removeDuplicates(arr, prop){
arr.forEach((a, i) => arr.slice(i+1).filter(e => e[prop] == a[prop]).forEach( el => {
if (arr.indexOf(el) > -1)
arr.splice(arr.indexOf(el), 1);
}));
return arr;
}
console.log(removeDuplicates(arr, 'Name'));

How to merge values from multiple objects into an object of arrays?

I have a two JSON something like below:
var obj1 = {
" name ":"rencho",
" age ":23,
" occupation ":"SE"
}
var obj2 = {
" name ":"manu",
" age ":23,
" country ":"india"
}
I want the expected output:
var result = {
"name":["rencho", "manu"],
"age":[23, 23],
"country":["-", "india"],
"occupation": ["SE", "-"],
}
However, I tried using below the code snippet:
let arrGlobal = []
arrGlobal.push(obj1);
arrGlobal.push(obj2);
let mergedResult = arrGlobal.reduce(function(r, e) {
return Object.keys(e).forEach(function(k) {
if(!r[k]) r[k] = [].concat(e[k])
else r[k] = r[k].concat(e[k])
}), r
}, {})
console.log(mergedResult);
But that one doesn't print - in json object. I would appreciate any kind of help from your side.
HELP WOULD BE APPRECIATED!!!
First get a list of all keys (needed in advance to check whether you need to add - while iterating), then use reduce to iterate over each object and add its values to the accumulator:
var obj1 = {
" name ":"rencho",
" age ":23,
" occupation ":"SE"
}
var obj2 = {
" name ":"manu",
" age ":23,
" country ":"india"
}
const arr = [obj1, obj2];
const allKeys = arr.reduce((keys, obj) => {
Object.keys(obj).forEach(key => keys.add(key))
return keys;
}, new Set());
const merged = arr.reduce((merged, obj) => {
allKeys.forEach((key) => {
if (!merged[key]) merged[key] = [];
merged[key].push(obj[key] || '-');
});
return merged;
}, {});
console.log(merged);
A slightly different approach by using a single loop for the outer array of objects and which generates all needed keys on the fly.
var obj1 = { name: "rencho", age: 23, occupation: "SE" },
obj2 = { name: "manu", age: 23, country: "india" },
hash = new Set,
result = {};
[obj1, obj2].forEach((o, length) => {
Object.keys(o).forEach(k => hash.add(k));
hash.forEach(k => {
result[k] = result[k] || Array.from({ length }).fill('-');
result[k].push(k in o ? o[k] : '-');
});
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
quick and dirty way:
function merge(a,b) {
var c = b
for (key in a){
c[key] = [c[key], a[key]]
}
console.log(c) //prints merged object
}
merge(obj1, obj2)

Categories

Resources