Converting array of object to en object with key : value dynamic - javascript

I have an array of objects which look like this:
stuff = [
{ value: 'elevator', checked: true },
{ value: 'something', checked: false },
{ value: 'else', checked: true },
]
And I am trying to get something like this:
{
'elevator': true,
'something: false,
'else': true,
}
All I can get since yesterday is an array of objects like:
[
{ 'elevator': true },
{ 'something': false },
{ 'else': true }
];
I tried with mapping on array and then using Object.assign but it's not working. I get the previous code.

Use reduce
var output = stuff.reduce( (a,c) => (a[c.value] = c.checked, a) , {} )
Demo
var stuff = [
{ value: 'elevator', checked: true },
{ value: 'something', checked: false },
{ value: 'else', checked: true },
];
var output = stuff.reduce( (a,c) => (a[c.value] = c.checked, a) , {} )
console.log( output );
Edit
Using object.assign
stuff.reduce( (a,c) => Object.assign( {}, a, { [c.value] : c.checked }) , {} )

Iterate stuff array, So you will get each object under stuff. Then get that value that you need.
var stuff = [
{ value: 'elevator', checked: true },
{ value: 'something', checked: false },
{ value: 'else', checked: true },
];
var obj = {};
for( var i=0; i<stuff.length; i++) {
obj[stuff[i]['value']] = stuff[i]['checked'];
}
console.log(obj);

You can reduce function to make an single object from the given array. Just add your logic inside it. In this case, value to the property name and checked to it's value.
const stuff = [
{ value: 'elevator', checked: true },
{ value: 'something', checked: false },
{ value: 'else', checked: true },
]
const mapped = stuff.reduce((obj, item) => (obj[item.value] = item.checked, obj), {});
console.log(mapped);

If you can use ES6, you can do it with Object.assign, array.prototype.map, some destructuring, object litteral dynamic key and spread operator:
var stuff = [
{ value: 'elevator', checked: true },
{ value: 'something', checked: false },
{ value: 'else', checked: true },
];
var result = Object.assign({}, ...stuff.map(({value, checked}) => ({[value]: checked})));
console.log(result);

Related

How to loop through array of objects and make key value pairs?

I have an array of objects like this:
let someObj = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
I want add this to an exiting object, where id is a key of this object, like this:
let obj = {
someKey: someValue,
'12': true,
'34': true,
'56': false,
}
You may achieve your goal using Array#reduce as follows:
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = input.items.reduce((o, {
id,
value
}) => (o[id] = value, o), {})
console.log(output)
Also, and maybe the simplest approach might be using Array#map to turn objects into pairs and then convert them into an object using Object.fromPairs:
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = Object.fromEntries(input.items.map(({
id,
value
}) => [id, value]))
console.log(output)
Finally, here's a functional approach:
// Composes two functions
const compose = f => g => x => f (g (x))
// Given the key-value pairs of some object with 2 properties, maps a pair of values
const values = ([[, x], [, y]]) => [x, y]
// Turns an object of two properties into a pair of property values
const entry = compose (values) (Object.entries)
// Turns many objects of two properties, into an object on which
// keys are first properties' values, and vaules the second properties' values.
const keyValueObject = xs => Object.fromEntries (xs.map (entry))
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = keyValueObject (input.items)
console.log(output)
You can iterate each item from items and create a new object as shown below.
let someObj = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const newObj = {};
someObj.items.map(item =>{
newObj[item.id]= item.value;
});
console.log(newObj);
Use map and Object.values will simplify.
const output = arr => Object.fromEntries(arr.map(Object.values));
let someObj = {
items: [
{
id: "12",
value: true,
},
{
id: "34",
value: true,
},
{
id: "56",
value: false,
},
],
};
console.log(output(someObj.items));
First, you can transform the itens into "KV" entries
> someObj.items.map(({id, value}) => [id, value])
[ [ '12', true ], [ '34', true ], [ '56', false ] ]
Then turn it into Object
> Object.fromEntries(someObj.items.map(({id, value}) => [id, value]))
{ '12': true, '34': true, '56': false }
You can do a function
> let ObjectFromMapping = (vs, mapping) => Object.fromEntries(vs.map(mapping))
> ObjectFromMapping(someObj.items, ({id, value}) => [id, value])
{ '12': true, '34': true, '56': false }
Maybe turn vs into a iterable is a good idea
> let ObjectFromMapping = (vs, mapping) => Object.fromEntries([... vs].map(mapping))
> ObjectFromMapping("abc", (char, idx) => [idx, char])
{ '0': 'a', '1': 'b', '2': 'c' }
Then your function will work on any iterable

Javascript lodash Filter Objects in Array based on value

I have the following array of objects:
var array = [
{
name: isSale,
value: true
},
{
name: isSale,
value: false
},
{
name: isNew,
value: true
}
]
I need to filter the array so that I have only 2 objects at the end:
var array = [
{
name: isSale,
value: true
},
{
name: isNew,
value: true
}
]
Meaning if I have both true and false values for the same name (isSale) I need to leave the object with the true value.
But if my array looks like this:
var array = [
{
name: isSale,
value: false
},
{
name: isNew,
value: true
}
]
meaning there is no duplicate isSale object it should stay like this and the object with the false value should not be removed from the array.
I prefer a solution with ES5 (you can write it in ES6/7 and transpile it with babel to ES5) and you can use lodash as well.
Thank you for the suggestions and cheers!
You could seach for same name in the result set and replace if the former value is false.
const
filter = array => array.reduce((r, o) => {
var index = r.findIndex(({ name }) => name === o.name)
if (index === -1) r.push(o);
else if (!r[index].value) r[index] = o;
return r;
}, []),
array1 = [{ name: 'isSale', value: true }, { name: 'isSale', value: false }, { name: 'isNew', value: true }],
array2 = [{ name: 'isSale', value: false }, { name: 'isNew', value: true }];
console.log(filter(array1));
console.log(filter(array2));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Descontruct array of objects to get nested values ES6

I have an array of objects like:
const array = [
{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false},
]
},
{
name: 'object2',
value: false,
}
];
I need to get value of each object in array.
To get object1 and object2 values I have used
const [{value: object1}, {value: object2}] = array;
How can I get values of objects which are in parameters array? How to deconstruct it in right way? Cannot find the right way..
You'd have to use parameters: and keep destructuring:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const [{ parameters: [
{ value: value1 },
{ value: value2 }
]}] = array;
console.log(value1, value2);
But that's not remotely readable IMO. I'd prefer to use standard dot/bracket notation to get to the parameters array, and .map to extract the values:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const values = array[0].parameters.map(({ value }) => value);
console.log(values);
You could take Array#flatMap and map the values of paramters only.
const
array = [{ name: 'object1', value: true, parameters: [{ name: 'inner1', value: true }, { name: 'inner2', value: false }] }, { name: 'object2', value: false }],
values = array.flatMap(({ parameters = []}) => parameters.map(({ value }) => value));
console.log(values);
The deconstruction must follow the shape of the object it is deconstructing. A good way to think of it in situations like this, is to just copy the object itself, and then replace each value with a variable name to assign that value to
// Object from which to deconstruct values
const myArray = [{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false}]
}];
// Deconstruction
const [{
name: nameVar,
value: valueVar,
parameters: [
{ name: paramNameVar1, value: valueVar1},
{ name: paramNameVar2, value: valueVar2}]
}] = myArray
Of course once you start getting more complex objects, it is possably more effort, less readable, and less efficient to deconstruct this way.

Desctructuring object with object arrays

I have this kind of and object:
obj: {
child1: [
{ type, checked, text, ... },
{ type, checked, text, ... },
{ type, checked, text, ... },
],
child2: [
{ type, checked, text, ... },
...
],
...
}
I need almost the same object, but child elements should have objects consisting only of type and checked values. Need my output to be like below example.
OUTPUT:
obj: {
child1: [
{
type: "type",
checked: "checked"
},
{
type: "type",
checked: "checked"
},
{
type: "type",
checked: "checked"
}
],
child2: [
{
type: "type",
checked: "checked"
}
]
}
So far everything I've tried doesn't seem to work.
My last failed attempt:
Object.keys(tabs).forEach(key =>
({
updatedState: {
[key]: (({ documentTypeId, checked }) => ({ documentTypeId, checked }))(tabs[key]),
},
}),
);
You can use Array.reduce() to iterate the object's keys, with an inner Array.map() and destructuring to create new objects from the properties you want to keep:
const type = 'type'
const checked = 'checked'
const text = 'text'
const obj = {
child1: [
{ type, checked, text },
{ type, checked, text },
{ type, checked, text },
],
child2: [
{ type, checked, text },
],
}
const result = Object.keys(obj).reduce((r, k) => {
r[k] = obj[k].map(({ type, checked }) => ({ type, checked }))
return r
}, {})
console.log(result)
You can use a combination of reduce (to iterate through the object keys) and map
(for your children arrays)
const obj = {
child1: [
{ type: 1, checked: true, text: 'aaa'},
{ type: 2, checked: false, text: 'bbb'},
{ type: 3, checked: true, text: 'ccc'}
],
child2: [
{ type: 4, checked: true, text: 'ddd'},
{ type: 5, checked: false, text: 'eee'},
{ type: 6, checked: true, text: 'fff'}
]
};
const result = Object.keys(obj).reduce((acc, key) => {
acc[key] = obj[key].map(child =>
({type: child.type, checked: child.checked}));
return acc;
}, {});
console.log(result);

Merge Array of Objects by Property using Lodash

I have two arrays of objects that represent email addresses that have a label and a value:
var original = [
{
label: 'private',
value: 'private#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
}
];
var update = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'school',
value: 'schhol#johndoe.com'
}
];
Now I want to compare and merge the two arrays by the label field, so that the result would look like this:
var result = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
},
{
label: 'school',
value: 'schol#johndoe.com'
}
]
How can I do this e.g. using lodash?
_.unionBy():
This method is like _.union except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which uniqueness is computed. Result values are chosen from the first array in which the value occurs.
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var update = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
var result = _.unionBy(update, original, "label");
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Convert the lists to objects keyed by label, merge them by _.assign, and convert it back to an array. It will even retain order of the items on most browsers.
var original = [
{
label: 'private',
value: 'private#johndoe.com'
},
{
label: 'work',
value: 'work#johndoe.com'
}
];
var update = [
{
label: 'private',
value: 'me#johndoe.com'
},
{
label: 'school',
value: 'schol#johndoe.com'
}
];
console.log(
_.map(
_.assign(
_.mapKeys(original, v => v.label),
_.mapKeys(update, v => v.label)
)
)
);
// or remove more duplicated code using spread
console.log(
_.map(
_.assign(
...[original, update].map(
coll => _.mapKeys(coll, v => v.label)
)
)
)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.js"></script>
Perhaps a bit late, but all the solutions I have seen don't join both arrays correctly, they use one of the arrays to loop on and any excess elements in the second array don't get added (assuming this is what is required).
The right way is to sort both arrays and move forward within both arrays, merging the matches elements and adding the missing elements from both arrays.
Please find full solution below. This also takes O(n+m) which is the best you can get (without the computational costs for sort itself). In my code I already got the data sorted from the database.
function mergeObjectsBasedOnKey(array1, array2, compareFn, mergeFn, alreadySorted) {
var array1Index = 0;
var array2Index = 0;
const merged = [];
if (!alreadySorted) {
array1.sort(compareFn);
array2.sort(compareFn);
}
while (array1Index < array1.length && array2Index < array2.length) {
var comparedValue = compareFn(array1[array1Index], array2[array2Index]);
if (comparedValue === 0) {
merged.push(mergeFn(array1[array1Index], array2[array2Index]));
array1Index++;
array2Index++;
} else if (comparedValue < 0) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
} else {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
}
while (array1Index < array1.length) {
merged.push(mergeFn(array1[array1Index]));
array1Index++;
}
while (array2Index < array2.length) {
merged.push(mergeFn(array2[array2Index]));
array2Index++;
}
return merged;
}
const array1 = [{
"id": 10,
isArray1: true
},
{
"id": 11,
isArray1: true
},
{
"id": 12,
isArray1: true
},
];
const array2 = [{
"id": 8,
isArray2: true
},
{
"id": 11,
isArray2: true
},
{
"id": 15,
isArray2: true
},
];
const result = mergeObjectsBasedOnKey(array1, array2, function(a, b) {
return a.id - b.id;
}, function(a, b) {
if (b) {
return _.merge(a, b);
}
return _.merge(a, {
isArray1: true,
isArray2: true
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
And the results would be:
[ { id: 8, isArray2: true, isArray1: true },
{ id: 10, isArray1: true, isArray2: true },
{ id: 11, isArray1: true, isArray2: true },
{ id: 12, isArray1: true, isArray2: true },
{ id: 15, isArray2: true, isArray1: true } ]
In case you are using lodash 3.x where _.unionBy() was not there, you can combine _.union() and _.uniq() to get the same result.
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var update = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
var result = _.uniq(_.union(update, original), "label");
console.log(result);
I know it is not what asked for but just in case someone stumbled up on this page here is how you do this in ramda:
var original = [
{ label: 'private', value: 'private#johndoe.com' },
{ label: 'work', value: 'work#johndoe.com' }
];
var updated = [
{ label: 'private', value: 'me#johndoe.com' },
{ label: 'school', value: 'schol#johndoe.com' }
];
unionWith(eqBy(prop('label')), updated, original);
Here is another way to merge two objects using Lodash:
let a = [{
content: 'aaa',
name: 'bbb2'
},
{
content: 'aad',
name: 'ccd'
}
];
let b = [{
content: 'aaa',
name: 'bbb'
},
{
content: 'aad1',
name: 'ccd1'
}
];
let c = [...a, ...b];
let d = _.uniq(c, function(data) {
return data.content;
})
console.log(d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
Perhaps a bit late, but all the solutions I have seen don't join both arrays correctly, they use one of the arrays to loop on and any excess elements in the second array don't get added (assuming this is what is required).
I had the same observation so put something together myself. This is working for my use case, which is to merge each object if the value of the 'label' field matches:
const dataSetHashes = dataSets.map(dataSet => _.keyBy(dataSet, 'label'))
const resultHash = _.merge(
{},
...dataSetLookups
)
const result = Object.values(resultLookup)

Categories