How to combine values in array by key? - javascript

I have data that looks like this:
data = [
[
{"name":"cpumhz","data":[[1433856538,0],[1433856598,0]]},
{"name":"mem","data":[[1433856538,13660],[1433856598,13660]]}
],
[
{"name":"cpumhz","data":[[1433856538,0],[1433856598,0]]},
{"name":"mem","data":[[1433856538,13660],[1433856598,13660]]}
],
[
{"name":"cpumhz","data":[[1433856538,0],[1433856598,0]]},
{"name":"mem","data":[[1433856538,13660],[1433856598,13660]]}
]
];
how would I use map to combine the array items so the data attributes are concatenated?
Like so:
data = [
[
{"name":"cpumhz","data":[[1433856538,0],[1433856598,0],[1433856538,0],[1433856598,0], [1433856538,0],[1433856598,0]]},
{"name":"mem","data":[[1433856538,13660],[1433856598,13660], [1433856538,13660],[1433856598,13660], [1433856538,13660],[1433856598,13660]]}
]
];
I'm getting closer by doing it non-programatically like so:
res = []
cpudata = _.flatten([data[0][0].data, data[1][0].data, data[2][0].data])
res.push({name: 'cpumhz', data: cpudata})
memdata = _.flatten([data[0][1].data, data[1][1].data, data[2][1].data])
res.push({name: 'mem', data: memdata})
http://jsbin.com/bekodirili/7/edit

Look into using the reduce function. Underscore/lodash have equivalent functions.
Essentially you want to take data and reduce it down to 1 array with 2 values. Something like the following should work:
var reducedData = data.reduce(function(prev, cur) {
prev.forEach(function(value, index) {
value.data = value.data.concat(cur[index].data);
});
return prev;
});
You go over each value in data and reduce it. You concat the previous sub-data with the current sub-data and return the new value.

With lodash, you can do something like this:
_(data)
.flatten()
.groupBy('name')
.reduce(function(result, item, key) {
return result.concat([{
name: key,
data: _.flatten(_.pluck(item, 'data'))
}]);
}, []);
You use flatten() to create an array that can then be grouped into an object, based on the name value using groupBy(). At this point, you have an object with two properties - cpuhz and mem.
Now it's easy to reduce() the object into the array you want.

Related

Access and extract values from doubly nested array of objects in JavaScript

I have an array of objects and within those objects is another object which contains a particular property which I want to get the value from and store in a separate array.
How do I access and store the value from the name property from the data structure below:
pokemon:Object
abilities:Array[2]
0:Object
ability:Object
name:"blaze"
1:Object
ability:Object
name:"solar-power"
How would I return and display the values in the name property as a nice string like
blaze, solar-power ?
I tried doing something like this but I still get an array and I don't want to do a 3rd loop since that is not performant.
let pokemonAbilities = [];
let test = pokemon.abilities.map((poke) =>
Object.fromEntries(
Object.entries(poke).map(([a, b]) => [a, Object.values(b)[0]])
)
);
test.map((t) => pokemonAbilities.push(t.ability));
Sample Data:
"pokemon": {
"abilities": [
{
"ability": {
"name": "friend-guard",
"url": "https://pokeapi.co/api/v2/ability/132/"
},
"ability": {
"name": "Solar-flare",
"url": "https://pokeapi.co/api/v2/ability/132/"
}
}
]
}
Then I am doing a join on the returned array from above to get a formatted string.
It just seems like the multiple map() loops can be optimized but I am unsure how to make it more efficient.
Thank you.
There is no need for a loop within loop. Try this:
const pokemon = {
abilities: [{
ability: {
name: 'friend-guard',
url: 'https://pokeapi.co/api/v2/ability/132/'
},
}, {
ability: {
name: 'Solar-flare',
url: 'https://pokeapi.co/api/v2/ability/132/'
}
}]
};
const pokemonAbilities = pokemon.abilities.map(item => item.ability.name).join(', ');
console.log(pokemonAbilities);

Find the element in json - Using underscore library or other way

I want to find the g:id object in the below given array of objects
If my g:id is like "g:id": "121"
I can find the element like
var item = _.findWhere(obj, {'g:id': '121'});
But what i have is "g:id": ["121"] like an array. How can i find it.
Here's my array of objects.
[
{
"g:id": [
"121"
],
"g:item_group_id": [
"90461"
]
},
{
"g:id": [
"129"
],
"g:item_group_id": [
"90462"
]
}
]
I tried like this var item = _.findWhere(jsonXML, {'g:id'.[0]: '121'}); but it is not valid.
How can i do this by underscore.js or any other way ?
You can use Array.find() with destructuring to get the g:id value from the array:
const arr = [{"g:id":["121"],"g:item_group_id":["90461"]},{"g:id":["129"],"g:item_group_id":["90462"]}]
const result = arr.find(({ 'g:id': [gid] }) => gid === '121')
console.log(result)
Another option is to use Array.includes() to see if the array contains the value (a must if the array may contain more the one value):
const arr = [{"g:id":["121"],"g:item_group_id":["90461"]},{"g:id":["129"],"g:item_group_id":["90462"]}]
const result = arr.find(({ 'g:id': gid }) => gid.includes('121'))
console.log(result)

How can I "unstack" my JSON data in d3.js?

I have data in a JSON array that looks like this:
[{"TEACHER":3.7},{"STUDENT":1.9}]
My desired output is a JSON array that looks like this:
var statements = [
{
name: "TEACHER",
value: 3.7
},
{
name: "STUDENT",
value: 1.9
}
];
How can I "unstack" the data I have to add the variable labels like I want?
This is what I came up with. There might be a more elegant way to do this though.
var x = [{"TEACHER":3.7},{"STUDENT":1.9}];
console.log(unstack(x));
function unstack(stacked){
var unstacked = [];
stacked.forEach((element) => {
unstacked.push({
name: Object.keys(element)[0],
value: Object.values(element)[0]
});
});
return unstacked;
}
Is it the only key your original object has? If that's the case, you can use the only item Object.keys() or Object.entries() return. If there are other attributes you could look for a match in the key and process it accordingly.
const input = [{"TEACHER":3.7},{"STUDENT":1.9}];
const output = [];
input.forEach(item => {
const key = Object.keys(item)[0];
output.push({name: key, value: item[key]});
});
console.log(output);

ES6 way - Get unique values from a nested array by key

trying to improve my JS chops.
Is there a cleaner way to retrieve the property value from the array below, by key, from a nested object, removing duplicates and sorting them alphabetically?
Here's what I have:
getObjectValues(array, key){
var unique = [];
array.forEach(function(item){
item[key].forEach(function(value){
if (unique.indexOf(value) < 0) {
unique.push(value)
}
})
});
return unique.sort();
},
example array of object:
[
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
expected output should be an array:
var array = ['a','b','c']
You could just use a Set, and add all the items to it:
let arr = [
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
console.log(
Array.from(
new Set(
arr.reduce(
(carry, current) => [...carry, ...current.value],
[]
)
)
).sort()
)
If you need something concise, you may go as simple as that:
make use of Set to get rid of duplicates
employ Array.prototype.flatMap() (with slight touch of destructuring assignment) to extract value items from within all objects into single array
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...new Set(src.flatMap(({value}) => value))].sort()
console.log(result)
.as-console-wrapper{min-height:100%;}
If you need something really fast, you may do the following:
use Array.prototype.reduce() to turn your array into Set of unique records (looping through value items with Array.prototype.forEach and doing Set.prototype.add())
spread resulting Set into array and .sort() that
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...src.reduce((acc,{value}) =>
(value.forEach(acc.add, acc), acc), new Set())].sort()
console.log(result)
.as-console-wrapper{Min-height:100%;}

Filter an empty array from a parent array

How can I completely remove an empty array from a parent array, before adding a new element.
I have a structure that looks like this
var parentArray = [ ['123', '345'], [], ['12'] ]
I want to remove array at index 1 before adding a new array.
I have tried this but it doesn't remove it:
parentArray.filter((array, index) => {
if (array.length === 0) {
parentArray.splice(index, 1);
}
})
parentArray.push(['435']);
console.log(parentArray); //Still give [["123", "345"], [], ["12"]]
You should not mutate your array in the filter method.
The callback function should return true if you want to keep the item, false if not.
const parentArray = [['123', '345'], [], ['12']];
const filteredArray = parentArray.filter( item => item.length !== 0);
console.log(filteredArray)
No need lodash or 3rd part libraries, here is what actually you needed,
var numbers = [ ['123', '345'], [], ['12'] ]
result = numbers.filter(x => x.length > 0);
console.log(result);
Use _.filter for that:
parentArray = _.filter(parentArray, function (array) {
return array.length > 0;
})
Ok, First of all as said above don't mutate any iterable while iterating through it.
and Array.filter returns a new array based on the condition given and it won't change the array on which it is being called.
if you want to keep the original parentArray and create a new array without the empty arrays in the parrentArray then do the following
let parentArray2 = parentArray.filter(e=>e.length !== 0)
this will give you the new array referenced by parentArray2 which will be
[ [ '123', '345' ], [ '12' ] ]
and parentArray remains as it is and then you can push a new array into parentArray2
if you don't want to retain the original parentArray then do the following
parentArray = parentArray.filter(e=>e.length !== 0)
the parent array will be initialized with a new array [ [ '123', '345' ], [ '12' ] ]
and then you can push any element are array or object into the parentArray
You can use lodash's _.reject() with _.isEmpty().
Reject removes an item if the predicate returns true, and isEmpty returns true for empty arrays.
var parentArray = [ ['123', '345'], [], ['12'] ]
var result = _.reject(parentArray, _.isEmpty)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Without lodash, you can use Array.filter(), and just return the length. Because 0 is falsy, and the item would be removed:
const numbers = [ ['123', '345'], [], ['12'] ]
const result = numbers.filter(o => o.length)
console.log(result)
The following code keeps the items which are not empty and stores them inside result.
const result = _.filter(parentArray, (item, i) => {
return !_.isEmpty(item);
});
console.log(result);

Categories

Resources