Related
My question is quite similar to this one: Merge keys array and values array into an object in JavaScript
However, I don't seem to find the solution for my example. If I have these two arrays:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
How do I combine them into an array of objects, such that would be the expected result?
[
{
x: 0,
y: 1,
z: 2,
},
{
x: 10,
y: 20,
z: 30,
},
]
You can use Array.prototype.map() and Array.prototype.reduce() for this:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const res = values.map(arr => arr.reduce((acc, curr, index) => {
acc[keys[index]] = curr
return acc;
}, {x: null, y: null, z: null}));
console.log(res);
Or you can also do it without reduce() like so:
const res = values.map(arr => ({
[keys[0]]: arr[0],
[keys[1]]: arr[1],
[keys[2]]: arr[2]
}));
Cycle through the value arrays and create an object for each, then cycle through the values within those arrays and use the keys array as the keys.
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const output = [];
values.forEach((v, i) => {
output[i] = {}; // create objects for each of the value arrays
v.forEach((w, j) => {
output[i][keys[j]] = w; // use the correct keys with each of the values
});
});
console.log(output);
As comments have also pointed out, this can be done with Array.reduce:
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
const output = values.map(x => { // for each of the values arrays
return x.reduce((a, c, i) => { // take its values
a[keys[i]] = c // map them to an object property one by one
return a; // put them together in the same object.
}, {});
});
console.log(output);
const keys = ['x', 'y', 'z'];
const values = [
[0, 1, 2],
[10, 20, 30],
];
function toObject(keys, values) {
let final = []
for (let i = 0; i < values.length; i++){
let result = {};
for(let j=0;j<keys.length;j++){
result[keys[j]] = values[i][j];
}
final.push(result)
}
return final
console.log(final)
}
toObject(keys,values )
it will work
This is a similar question as this one: Complete missing sequence in array with zeros in javascript
However, I can't seem to go around this problem. This is my array:
const array = [
[5, 'a', 2.3],
[6, 'a', 1.7],
[7, 'a', 5.4],
[8, 'a', 2.8],
[9, 'a', 8.5],
[10, 'a', 9.2],
[2, 'b', 1.6],
[5, 'b', 5.7],
[6, 'b', 8.9],
[7, 'b', 3.5],
[8, 'b', 6.1],
[9, 'b', 1.8],
[10, 'b', 7.4],
];
console.log(array);
First element: this is my reference value, it ranges from 1 to 10.
Second element: this is a category value.
Third element: this is a value that belongs to the second element, which happened at a timestamp that belongs to the first element.
My issue: I need to make sure that all the unique categories in the second element of the array (e.g., a and b) have the following sequence in the first element: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. If they do not have one of these numbers, then I need to create it, and then assign null to the third element.
Therefore, this is my expected output:
[
[1, 'a', null],
[2, 'a', null],
[3, 'a', null],
[4, 'a', null],
[5, 'a', 2.3],
[6, 'a', 1.7],
[7, 'a', 5.4],
[8, 'a', 2.8],
[9, 'a', 8.5],
[10, 'a', 9.2],
[1, 'b', null],
[2, 'b', 1.6],
[3, 'b', null],
[4, 'b', null],
[5, 'b', 5.7],
[6, 'b', 8.9],
[7, 'b', 3.5],
[8, 'b', 6.1],
[9, 'b', 1.8],
[10, 'b', 7.4],
];
Any ideas?
You can create a range from 1 to 10, loop over it and when you can't find an association in your array, create a new element and push it.
Do that for every category and you're good.
const range = new Array(0).fill().map((_, i) => i + 1); // from 1 to 10
const categories = array
.map(x => x[1]) // get categories
.filter((val, i, self) => self.indexOf(val) === i) // uniq
categories.forEach(categ => {
range.forEach(n => {
const alreadyInArray = array.some(x => x[0] === n && x[1] === categ);
if (!alreadyInArray) {
const newEntry = [n, categ, null];
array.push(newEntry);
}
});
})
You can of course replace the forEach with classic for loops
A functional solution, first get the categories, then for each category fill the corresponding array.
const array = [
[5, 'a', 2.3],
[6, 'a', 1.7],
[7, 'a', 5.4],
[8, 'a', 2.8],
[9, 'a', 8.5],
[10, 'a', 9.2],
[2, 'b', 1.6],
[5, 'b', 5.7],
[6, 'b', 8.9],
[7, 'b', 3.5],
[8, 'b', 6.1],
[9, 'b', 1.8],
[10, 'b', 7.4],
];
const getMissingIndicesFromCategory = (tuples) => {
const indices = tuples.map(tuple => tuple[0])
const fullIndices = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
return fullIndices.filter(index => !indices.includes(index));
}
const createMissingTuples = (missingIndices, category) => {
return missingIndices.map(index => [index, category, null])
}
const completeCategoryTuples = (array, category) => {
const categoryTuples = array.filter(tuple => tuple[1] === category)
const missingIndices = getMissingIndicesFromCategory(categoryTuples)
const missingTuples = createMissingTuples(missingIndices, category)
return [...categoryTuples, ...missingTuples].sort((tuple1, tuple2) => tuple1[0] > tuple2[0] ? 1 : -1)
}
const getAllUniqueCategories = (array) => Array.from(new Set(array.map(tuple => tuple[1])))
const fillArray = (array) => {
const categories = getAllUniqueCategories(array)
return categories.flatMap(category => completeCategoryTuples(array, category))
}
const fullArray = fillArray(array)
console.log(fullArray)
I have an array that looks something like this:
currArray =
[
['a', 2],
['b', 3],
['c', 5],
['a', 2],
['b', 4],
['d', 6]
]
I am trying to combine the arrays that have the same value at [0], while adding the values at [1]. So the output would look like:
newArray =
[
['a', 4],
['b', 7],
['c', 5],
['d', 6]
]
Currently trying this via Vanilla JavaScript and lodash.
Any advice is much appreciated.
You can use Array.reduce():
const currArray = [
['a', 2],
['b', 3],
['c', 5],
['a', 2],
['b', 4],
['d', 6]
];
const result = currArray.reduce((res, [key, val]) => {
const correspondingArr = res.find(arr => arr[0] === key);
if (correspondingArr) {
correspondingArr[1] += val;
} else {
res.push([key, val]);
}
return res;
}, []);
console.log(result);
We can use hashmaps to store the sum, and then map the hashmap to array.
currArray =
[
['a', 2],
['b', 3],
['c', 5],
['a', 2],
['b', 4],
['d', 6]
]
// create a hash map
const currArrInfo = {};
// fill the hash map
currArray.forEach((miniArray) => {
currArrInfo[miniArray[0]] = currArrInfo[miniArray[0]] || 0;
currArrInfo[miniArray[0]]+=currArrInfo[miniArray[1]];
});
// map the hash map to array
currArray = Object.keys(currArrInfo).map((key) => [key, currArrInfo[key]]);
You can use _.groupBy() with _.head() to group all entries with the same 1st item. Then map the groups, and sum (with _.sumBy() and _.last()) the 2nd elements of each group:
const currArray = [["a",2],["b",3],["c",5],["a",2],["b",4],["d",6]]
const result = _.map(
_.groupBy(currArray, _.head), // group by the 1st item
(group, key) => [key, _.sumBy(group, _.last)] // take the key from each group, and sum all the 2nd items of each group
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
With lodash/fp you can create a function with _.flow() that groups the items by the 1st element, sum the 2nd elements of each group, and convert to entries:
const { flow, groupBy, head, mapValues, sumBy, last, toPairs } = _
const fn = flow(
groupBy(head), // group by the 1st item
mapValues(sumBy(last)), // take the key from each group, and sum all the 2nd items of each group
toPairs // convert to entries
)
const currArray = [["a",2],["b",3],["c",5],["a",2],["b",4],["d",6]]
const result = fn(currArray)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You could use a Map to keep a running tally for each differing currArray[0]:
currArray =
[
['a', 2],
['b', 3],
['c', 5],
['a', 2],
['b', 4],
['d', 6]
];
let map = new Map();
currArray.forEach(function(subAry)
{
let runningTally = map.get(subAry[0]);
if (runningTally)
{
map.set(subAry[0],runningTally + subAry[1]);
}
else
{
map.set(subAry[0],subAry[1]);
}
});
let newArray = Array.from(map);
console.log(newArray);
Is there any shorthand method to convert array of string array with header as first array (Input as shown below) to Objects of array (as expected output shown below)
Using for loop we can achieve this, I am looking for any short hand and optimized solution to do this.
Let me know if is there any easy and optimized method to implement this.
Input
[
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
]
Expected Output :
[{
fromAge : 0,
toAge: 10,
gender: "F",
institutionalRaf : "1.5"
},
{
fromAge : 11,
toAge: 20,
gender: "F",
institutionalRaf : "2.5"
}
...
]
You can use map and reudce
Take the first element as header and rest of element as values
Loop through the values array for each element build a object with key from header and value from element
let data = [["fromAge","toAge","gender","institutionalRaf"],["1",'4','m','12'],["4",'12','f','22'],["10",'20','m','109']]
let [header,...values] = data
let final = values.map(v=> {
return v.reduce((op,inp,index)=>{
op[header[index]] = inp
return op
},{})
})
console.log(final)
You could separate the keys and the values and map the value as object with the keys.
var array = [['fromAge', 'toAge', 'gender', 'institutionalRaf'], [0, 10, 'F', '1.5'], [11, 20, 'F', '2.5']],
[keys, ...values] = array,
result = values.map(a => Object.assign(...keys.map((k, i) => ({ [k]: a[i] }))));
console.log(result);
I'd shift out the first array of keys, then .map to create entries and create the objects using Object.fromEntries:
const arr = [
['a', 'b', 'c'],
[1, 2, 3],
[4, 5, 6]
];
const keys = arr.shift();
const output = arr.map(values =>
Object.fromEntries(
values.map((value, i) => [keys[i], value])
)
);
console.log(output);
Object.fromEntries is a relatively new method. On older environments, either use a polyfill, or create the object with reduce instead:
const arr = [
['a', 'b', 'c'],
[1, 2, 3],
[4, 5, 6]
];
const keys = arr.shift();
const output = arr.map(values => (
values.reduce((a, value, i) => {
a[keys[i]] = value;
return a;
}, {})
));
console.log(output);
If keys are fixed we can use the simple approach like below
let arr=[
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
];
let arr1=arr.slice();
let x=arr1.shift();
let x1=arr1.map(a=>(
{
[x[0]]:a[0],
[x[1]]:a[1],
[x[2]]:a[2],
[x[3]]:a[3],
}
)
)
console.log(x1);
Use destructuring, map and reduce
const array = [
['fromAge', 'toAge', 'gender', 'institutionalRaf'],
[0, 10, 'F', '1.5'],
[11, 20, 'F', '2.5']
]
const [keys, ...values] = array
const result = values.map((value) => value.reduce((a, b, index) => ({...a, [keys[index]]: b}), {}), [])
console.log("result",result)
I am having a array in the format:
const resultData = [
[1, 2, 'a', 'b'],
[1, 4, 'c', 'f'],
[2, 5, 'a', 'b'],
[1, 2, 'c', 'd'],
[9, 3, 'c', 'f'],
[5, 4, 'f', 'g']
]
and I am trying to convert in in the format:
[{
value: "a,b",
data: [
[1, 2],
[2, 5]
]
}, {
value: "c,f",
data: [
[1, 4],
[9, 3]
]
}, {
value: "c,d",
data: [
[1, 2]
]
}, {
value: "f,g",
data: [
[5, 4]
]
}]
I am using a map currently with a for loop:
var mapp = new Map;
_.each(resultData, item => {
var x = item.col.slice(2);
if (mapp.has(x.toString())) {
var temp = mapp.get(x.toString());
temp.push([item.col[0], item.col[1]]);
mapp.set(x.toString(), temp);
} else {
var valuesArray = [];
valuesArray.push([item.col[0], item.col[1]])
mapp.set(x.toString(), valuesArray);
}
});
I am having a huge data set. Is there a possible way to do it without a loop or any other method?
You can make use of reduce and Object.values method like below
const resultData = [[1,2,'a','b'],[1,4,'c','f'],[2,5,'a','b'],[1,2,'c','d'],[9,3,'c','f'],[5,4,'f','g']]
const res = resultData.reduce((acc, item) => {
const key = item.slice(2).join();
const value = item.slice(0, 2);
if(!acc[key]) {
acc[key] = {value: key, data: [value]};
} else {
acc[key] = {...acc[key], data: [...acc[key].data, value]}
}
return acc;
}, {});
console.log(Object.values(res));
I would use reduce to generate the results:
check if the key values already exists
If it does, append the new items to the data array
If it does not, create the new object with the data
const resultData = [
[1, 2, 'a', 'b'],
[1, 4, 'c', 'f'],
[2, 5, 'a', 'b'],
[1, 2, 'c', 'd'],
[9, 3, 'c', 'f'],
[5, 4, 'f', 'g']
]
let result = resultData.reduce((arr, itm) => {
let value = itm[2] + ',' + itm[3]
let item = arr.find(i => i.value == value)
if (!item) arr.push({ value, data: [[itm[0], itm[1]]] })
else item.data.push([itm[0], itm[1]])
return arr
}, [])
console.log(result)
Javascript arrays have a .map method:
var newArray = resultData.map(function(arrayMember){
var objectToReturn = {};
objectToReturn['value'] = arrayMember; // add other transformations
return objectToReturn;
}); // map
another solution:
const res = _.chain(resultData)
.groupBy(item => _.takeRight(item, 2).join(','))
.mapValues((items, value) => ({
value,
data: _.map(items, arr => _.take(arr, 2))
}))
.values()
.value();