Reputation: 2507
I would like to create an object containing all the values from the array first and the values from second as an array of values, assuming that this key references multiple numbers such that given the arrays:
first = [3,0,5,3]
second = [1,3,10,5]
my output would be {0: 3, 3: [1,5], 5: 10}
This is what I have tried:
const newObj = {}
for(let i = 0; i < first.length; i++){
newObj[first[i]] = second[i] ? [ second[i] ] : second[i]
}
This is what I get:
{ '0': [ 3 ], '3': [ 5 ], '5': [ 10 ] }
Upvotes: 0
Views: 78
Reputation: 8536
This is my suggestion for it, using Array.reduce
, spread syntax and computed property names
first.reduce((o, k, i) => ({ ...o, [k]: [...o[k]||[], second[i]] }), {})
first = [3,0,5,3]
second = [1,3,10,5]
output = first.reduce((o, k, i) => ({ ...o, [k]: [...o[k]||[], second[i]] }), {})
console.log(output)
You can find detailed explanation on this strategy in this other answer.
Upvotes: 0
Reputation: 33691
I would collect all the values into arrays, regardless of how many there are (the transform
function below does this) — having a data structure with uniform types is more predictable/easier to work with.
Then, in a subsequent step, the single element from the arrays with only one element can be extracted (the extractSingleArrayElements
function below does this). See comments in the code for explanation:
'use strict';
/**
* Takes an array of keys and an array of values, and returns an object
* with values collected in arrays grouped by the keys that match their indexes
*
* @param {number[]} keys Array of integer keys
* @param {number[]} values Array of integer values
* @returns {Record<string, number[]>}
*/
function transform (keys, values) {
// Ensure that the lengths of the arrays are the same before proceeding:
if (keys.length !== values.length) throw new Error('Input lengths differ');
const result = {};
for (let i = 0; i < values.length; i += 1) {
const key = keys[i];
const value = values[i];
// Create a refrence to the array of values at the key,
// first creating and assigning it to the object at the key
// if it doesn't already exist:
const array = (result[key] ??= []);
array.push(value);
}
return result;
}
/**
* Takes an object with array values and returns a shallow copy of the object,
* replacing any array values that have only one element with the element itself
*
* @param {Record<string, number[]>} obj
* @returns {Record<string, number | number[]>}
*/
function extractSingleArrayElements (obj) {
const result = {};
for (const [key, array] of Object.entries(obj)) {
result[key] = array.length === 1 ? array[0] : array;
}
return result;
}
const keys = [3, 0, 5, 3];
const values = [1, 3, 10, 5];
const transformed = transform(keys, values);
const actual = extractSingleArrayElements(transformed);
const expected = {0: 3, 3: [1, 5], 5: 10};
console.log(JSON.stringify(actual) === JSON.stringify(expected)); // true
Upvotes: 0
Reputation: 20376
You can loop through all the items. You have three conditions for every array element you get. You will try to map it to a key of your new object you are creating and these will be the cases:
const first = [3,0,5,3];
const second = [1,3,10,5];
const ans = {};
first.forEach((curr,index) => {
if(Array.isArray(ans[curr])){ ans[curr] = [...ans[curr],second[index]];
}
else{
if(ans[curr]){ans[curr] = [ans[curr],second[index]];
}
else ans[curr] = second[index];
}
});
console.log(ans);
Upvotes: 0
Reputation: 26307
This is the easiest method to understand as it's just the bare logic written in its entirety.
for (let i = 0; i < first.length; i++) {
if (first[i] in newObj) { // If key exists already
if (typeof newObj[first[i]] === "number") { // and if it's a number
newObj[first[i]] = [newObj[first[i]]]; // then we wrap it into an array
}
newObj[first[i]].push(second[i]); // add the new number
} else {
newObj[first[i]] = second[i]; // if it doesn't exist then add it
}
}
Upvotes: 1