Combining JS object keys - javascript

I want to combine keys without overwriting the original.
Previously, I had issues with .assign considering some keys are overwritten.
Example of what I'd like:
In:
a = {
first: [1, 2, 3],
second: [5]
}
b = {
first: [5],
second: [6, 7, 8]
}
Out:
{
first: [1, 2, 3, 5],
second: [5, 6, 7, 8]
}
What I've tried:
const c = {...a, ...b}
And:
Object.assign(a, b);
These look to produce similar if not same results.
Lastly:
concat()
But I may have not used the syntax correctly and wasn't able to get a result.

There's no built in assign or spread or so for what you're trying to achieve here.
You have to do it explicitly. Like this, for example:
const a = {
first: [1, 2, 3],
second: [5]
}
const b = {
first: [5],
second: [6, 7, 8]
}
// I want a new Object ...
const out = {
// with a property "first", that consists of
// the items in `a.first` followed by them in `b.first`
first: [...a.first, ...b.first],
// and the same for the property "second"
second: [...a.second, ...b.second],
}
console.log(out);

You might want to create a generic case:
//all objects
const objs = [
{first: [1, 2, 3], second:[5]},
{first: [5], second: [6, 7, 8]},
{first: [3, 4], second: [5, 6]}
]
//unique keys
const unique_keys = new Set([].concat.apply([],objs.map(Object.keys)));
//unified object
const unified_obj = [...unique_keys].reduce((o, key) => {
o[key] = objs.map(e => e[key]).reduce((a, e) => a.concat(e), []);
return o;
}, {});
To get unique keys it's a bit more complex than Object.keys(Object.assign(...objs)), but performs better, as it doesn't deal with values at all.

Related

How would one remove all keys on an object which are not present in an Array in JavaScript?

Let's say I got this array
const items = ["foo", "bar", "baz"];
and I got this object
const _obj = {
foo: [1, 2, 3],
bar: [1, 2, 3],
baz: [1, 2, 3],
moo: [1, 2, 3],
tee: [1, 2, 3]
};
I would like to have all the object keys removed which are not present in the items array.
So the result should be:
const _newObj = {
foo: [1, 2, 3],
bar: [1, 2, 3],
baz: [1, 2, 3]
}
As you can see, the properties moo and tee are not present in the object anymore, since they are not items of the array.
I will use it like this:
const [obj, setObj] = useState({
foo: [1, 2, 3],
bar: [1, 2, 3],
baz: [1, 2, 3],
moo: [1, 2, 3],
tee: [1, 2, 3]
});
const update = () => {
setObj(prevObj => {
// the magic should happen here
return { ...prevObj };
});
}
How would I accomplish this..?
You could map new entries and get a new object from it.
const
items = ["foo", "bar", "baz"],
object = { foo: [1, 2, 3], bar: [1, 2, 3], baz: [1, 2, 3], moo: [1, 2, 3], tee: [1, 2, 3] },
result = Object.fromEntries(items.map(key => [key, object[key]]));
console.log(result);
A version which keeps the same object reference.
const
items = ["foo", "bar", "baz"],
object = { foo: [1, 2, 3], bar: [1, 2, 3], baz: [1, 2, 3], moo: [1, 2, 3], tee: [1, 2, 3] };
Object
.keys(object)
.filter(key => !items.includes(key))
.forEach(Reflect.deleteProperty.bind(null, object));
console.log(object);
Maybe using reduce:
const _newObj = Object.entries(_obj).reduce((acc, el) => {
const [key, value] = el;
if(items.includes(key)){
acc[key] = value;
}
return acc;
},{});
You can use the "hasOwnProperty" function to detect if that object has a property by a certain name. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
Dummy code:
for (int i = 0; items.length; i++) {
if (_obj.hasOwnProperty(items[i]) {
delete _obj[items[i]];
}
}
}
If you want it to be a new object, you could build the object instead of doing a delete on the existing one. hasOwnProperty is supported in all browsers, where the other answer (fromEntries) will require a polyfill for Internet Explorer.

Assigning key's to array objects

I'm trying to solve this problem. Essentially, I have a array of keys, and an array of values within objects, and I want those values to have keys.
Below is my best attempt so far - usually use python so this is a bit confusing for me.
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
var result = [];
for (arr in selection) {
numbers.forEach(function (k, i) {
result[k] = arr[i]
})
};
console.log(result);
The output I'm looking for is like this,
results = [{3:1,4:2,5:3,6:4}, {..},..]
Love some pointers to getting the right output.
Note. This is for google appscript! So can't use certain javascript functions (MAP I think doesn't work, unsure of reduce).
Cheers!
Use map on selection and Object.assign
var numbers = [3, 4, 5, 6];
var selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4]
];
var result = selection.map(arr =>
Object.assign({}, ...arr.map((x, i) => ({ [numbers[i]]: x })))
);
console.log(result);
Create a separate function which take keys and values as arguments and convert it into object using reduce(). Then apply map() on selections and make an object for each subarray using that function
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
function makeObject(keys, values){
return keys.reduce((obj, key, i) => ({...obj, [key]: values[i]}),{});
}
const res = selection.map(x => makeObject(numbers, x));
console.log(res)
Create a new object from scratch for each number array:
const selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4],
];
function objMaker(numarr) {
const numbers = [3, 4, 5, 6];
numarr.forEach((num, i) => (this[numbers[i]] = num));
}
console.info(selection.map(numarr => new objMaker(numarr)));

Combine arrays of identical length into array of objects

I have 10 arrays of data that look like this:
var arr = [1,2,3,4,5,6,7,8,9,10]
var arr2=['hello','hello1','hello2','hello3','hello4','hello5','hello6','hello7','hello8','hello9']
...8 More Arrays
Each array will have exactly the same number of elements every time. I wanted to know the best way to generate an array of objects that look like this that combines the various arrays:
overallarray = [{
arr1 = 1,
arr2 = 'hello'
...
},
{
arr1 = 2,
arr2 = 'hello1'
...
}]
I recognize that I can use a large number of for loops but am looking for a more optimized solution that someone might have.
This is where Array.map() will be your friend. You can iterate through any of the arrays (since they have the same number of elements) and then access each element by index to get the corresponding value for each array in your dataset, like so:
var arr = [0,1,2,3,4,5,6,7,8,9]
var arr2=['hello','hello1','hello2','hello3','hello4','hello5','hello6','hello7','hello8','hello9'];
var arr3=['foo','foo1','foo2','foo3','foo4','foo5','foo6','foo7','foo8','foo9'];
let mapped = arr.map((elem, index) => {
return {
arr1: arr[index],
arr2: arr2[index],
arr3: arr3[index]
}
});
console.log(mapped);
Edit: If you wanted to access them generically, you can add all of your arrays to one dictionary and iterate over the key/value pairs, like so:
var arr = [0,1,2,3,4,5,6,7,8,9]
var arr2=['hello','hello1','hello2','hello3','hello4','hello5','hello6','hello7','hello8','hello9'];
var arr3=['foo','foo1','foo2','foo3','foo4','foo5','foo6','foo7','foo8','foo9'];
// combine all arrays into single dataset
let data = {arr, arr2, arr3};
let mapped = arr.map((elem, index) => {
// iterate over the key/value pairs of the dataset, use the key to generate the
// result object key, use the value to grab the item at the current index of the
// corresponding array
return Object.entries(data).reduce((res, [key, value]) => {
res[key] = value[index];
return res;
}, {});
});
console.log(mapped);
Assuming arr1,arr2 are not desired names of resulting object properties, if you need something
that scales nicely for arbitrary number of data arrays
assigns arbitrary key names (not necessarily corresponding to array variable names, or, worse, property name(s) that can't be valid variable name are needed)
works muuuch faster than accepted solution ;)
You may do the following:
const arr1 = [1,2,3,4,5,6,7,8,9,10],
arr2=['hello','hello1','hello2','hello3','hello4','hello5','hello6','hello7','hello8','hello9'],
keyNames = ['id', 'greeting'],
group = (...arrays) => (keys) =>
arrays.reduce((res, arr, idx) =>
(arr.forEach((e,i) => res[i][keys[idx]] = e), res),
Array.from({length:arrays[0].length}, () => ({}))
)
console.log(group(arr1,arr2)(keyNames))
.as-console-wrapper {min-height:100%;}
Just iterate all arrays with 1 loop counter:
var dataArrayOne = [1, 2, 3, 4 ];
var dataArrayTwo = ["hello", "hello1", "hello2", "hello3" ];
...
var resultArray = [];
for (var i = 0; i < 4; i++)
{
var combined = {
arr1: dataArrayOne[I],
arr2: dataArrayTwo[i]
...
};
resultArray.push(combined);
}
You can get from this:
[ [1, 2, 3]
, [4, 5, 6]
, [7, 8, 9]
]
to this:
[ [1, 4, 7]
, [2, 5, 8]
, [3, 6, 9]
]
with this function:
const combine =
(...arrs) =>
[ arrs.map(xs => xs[0])
, ... ( arrs.every(xs => xs.length === 1)
? []
: combine(...arrs.map(xs => xs.slice(1)))
)
];
combine
( [1, 2, 3]
, [4, 5, 6]
, [7, 8, 9]
);
Then from this:
[ [1, 4, 7]
, [2, 5, 8]
, [3, 6, 9]
]
to this:
[ {arr1: 1, arr2: 4, arr3: 7}
, {arr1: 2, arr2: 5, arr3: 8}
, {arr1: 3, arr2: 6, arr3: 9}
]
with this function:
const to_obj =
(...arrs) =>
arrs.map(arr =>
Object.fromEntries(
arr.map((x, i) => [`arr${i+1}`, x])));
to_obj
( [1, 4, 7]
, [2, 5, 8]
, [3, 6, 9]
)
Hopefully connecting the two functions together is straightforward.
A note about performance
With exactly 10 arrays of 10 elements each, it is unlikely that you can tell whether a particular solution performs better than another. You should probably go for the solution that feels right in terms of readability or maintenance.
By these criteria you should probably exclude mine; just wanted to share a different approach.

How to convert array to object in JavaScript

I want to convert the following array:
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
to the following object:
const data = [
{
a: 1,
b: 2,
c: 3,
d: 4
},
{
a: 5,
b: 6,
c: 7,
d: 8
},
{
a: 9,
b: 10,
c: 11,
d: 12
}
];
How do I do it using loop or some other way, of course?
This is a basic map / reduce operation where you map the outer array to a new one where each value (array) is reduced to a single object.
Given the simple nature of each value (a single array with four values), you can skip Array.prototype.reduce() for some array destructuring.
For example
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
const newData = data.map(([ a, b, c, d ]) => ({ a, b, c, d }))
console.info(newData)
Note that this really hinges on knowing the data structure and no surprises (more or fewer elements in each array for example).
If you wanted a much more robust version, you'll want something like this
const data = [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10, 11, 12]];
const newData = data.map(arr => arr.reduce((obj, val, idx) => ({
...obj,
[String.fromCharCode(97 + idx)]: val
}), Object.create(null)))
console.info(newData)
The only thing to worry about here is if your arrays contain more than 26 elements. Then your object keys are going to get weird.
You can use Array.prototype.map() combined with Array.prototype.reduce()
Code:
const alphabet = [...'abcdefghijklmnopqrstuvwxyz'];
const data = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
const reasult = data.map(arr => arr.reduce((a, c, i) => (a[alphabet[i]] = c, a), {}));
console.log(reasult);

Convert an Array to unique values only while maintaining the correct sequence

I have the following code:
function uniteUnique(arr) {
//Create a single Array of value
arr = arguments[0].concat(arguments[1], arguments[2]);
//Reduce the Array to unique values only
arr = arr.reduce((pre, curr) => {
//Some function to reduce values
});
return arr;
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
The goal is to produce a single Array containing only unique values while maintaining the order.
Currently it returns:
[1, 3, 2, 5, 2, 1, 4, 2, 1]
I'm wanting to reduce this to:
[1, 3, 2, 5, 4]
You can use Set for that:
function uniteUnique(...args) {
return [...new Set([].concat(...args))];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
It maintains insertion order, and by nature only contains unique values.
In ES5 you could do it by maintaining the used values as properties of a temporary object, while building the result array:
function uniteUnique(/* args */) {
return [].concat.apply([], arguments).reduce(function (acc, v) {
if (!acc[0][v]) acc[0][v] = acc[1].push(v); // assigns new length, i.e. > 0
return acc;
}, [ Object.create(null), [] ])[1];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
You can use the Set object since it already keeps your values unique in one object:
const mySet = new Set([1, 3, 2, 5, 2, 1, 4, 2, 1]);
// returns: Set { 1, 3, 4, 5 };
const arrayUniques = [...mySet];
console.log(arrayUniques);
// returns: [1, 3, 4, 5];

Categories

Resources