I am having what I think is a pretty trivial problem but somehow I can't find a solution to. I have a response body that looks like this:
{
"sizes": [
{
"43": 35
},
{
"42": 20
},
{
"38": 10
}
]
}
where the keys are shoe sizes and the value is quantity of each size. How do I access the sizes? What I currently have is this:
const sizesArray = response.data.sizes
const arr = Object.values(msizes);
console.log('arr', arr);
arr.map((i,a) => {
console.log('i',i);
console.log('a',a);
})
but i is then again a object {43: 35}
and a is just the index. I want somehow to assign the key to parameter called 'sizes' and the key to a parameter called quantity.
You can use Object.keys, a bit simpler than Object.entries
Example:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] };
const result = data.sizes.map((element, index) => {
let obj = Object.keys(element); // returns an array of keys
let key = obj[0]; // first element is the only key
let quantity = element[key]; // bracket notation, key is an string, not number
console.log("size", key);
console.log("quantity", quantity);
});
You can just iterate the sizes array, using reduce to append the keys of each object to an output array of sizes:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] }
const sizes = data.sizes.reduce((acc, s) => acc.concat(Object.keys(s)), [])
console.log(sizes)
If you want sizes and quantities, you can take a similar approach, just generate an object which accumulates both sets of values:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] }
const { sizes, quantities } = data.sizes
.reduce((acc, s) => {
acc.sizes = acc.sizes.concat(Object.keys(s))
acc.quantities = acc.quantities.concat(Object.values(s))
return acc
},
{ sizes : [], quantities : [] })
console.log(sizes)
console.log(quantities)
You were on the right track :)
Use Object.keys() to get an array of your keys (shoe-sizes). Then use the map()-function to create a new array. Use the index of map() to access the quantity in your response.
const sizesArray = response.data.sizes
const sizes = Object.keys(sizesArray);
const result = sizes.map((element, index) => ({
size: element,
quantity: sizesArray[index]
}));
console.log(result);
Related
if I have an array of strings like:
['person,item,cost,amount',
'John,shoes,200,2']
how could I convert this into an object that resembles:
{
'John':[
{
item:'shoes',
cost:'200',
amount:'2',
totalPriceForItems:'400'
}
If I understand correctly, you may try something like this:
const convert = data => {
const [columnsText, ...items] = data;
const columns = columnsText.split(',');
return items.reduce((acc, text) => {
const { person, ...entries } = Object.fromEntries(text.split(',').map((value, i) => [columns[i], value]));
entries.totalPriceForItems = String(entries.cost * entries.amount);
if(acc[person]) {
acc[person].push(entries);
} else {
acc[person] = [entries];
}
return acc;
}, {});
};
const result = convert([
'person,item,cost,amount',
'John,shoes,200,2',
'Bob,glasses,50,3',
'John,shirts,100,5',
]);
console.log(result);
According to your comment,
I have 8 lines of 'John,shoes,200,2' but with different amounts in the
same array. The 'person,item,cost,amount' is only mentioned once at
the start of the array
What I understand is that you have a csv with headers and multiple rows.
If that is the case, then your data would resemble something like this:
data = [
'person,item,cost,amount',
'John,shoes,200,2',
'Adam,pants,60,1',
'Kelly,skirt,180,2',
'John,skirt,150,3'
]
Then you could consider the following approach, that is generic enough to adapt to different headers, and multiple data rows with repeated keys (person names).
// here, you define a function to transform each row of your data,
// like parsing numeric attributes and calculating the totals
function transform(row) {
row.cost = Number.parseInt(row.cost)
row.amount = Number.parseInt(row.amount)
row.total = row.cost * row.amount
return row
}
// The following logic is generic, and can be used
// to map and aggregate any kind of csv with headers
hdrs = data.shift().split(',').slice(1)
rows = data.map(r => r.split(',')).reduce((acc, [n, ...kvs]) =>
({ ...acc, [n]: [...acc[n] || [], transform(Object.fromEntries(kvs.map((v, i) => [hdrs[i], v])))] }), {})
Output:
{
John: [
{ item: "shoes", cost: 200, amount: 2, total: 400 },
{ item: "skirt", cost: 150, amount: 3, total: 450 }],
Adam: [
{ item: "pants", cost: 60, amount: 1, total: 60 }],
Kelly: [
{ item: "skirt", cost: 180, amount: 2, total: 360 }]
}
I have this array above and I need every property of it
let arr = [{'John': 0}, {'Doe': 50}, {'Marry': 100}]
How could I extract every single key/value of it, once in theory, I don't know any of them?
I have already tried using object.keys but it returns the indexes of my array.
This should work
const arr = [{'John': 0}, {'Doe': 50}, {'Marry': 100}];
// to iterate over each element in the arry
arr.forEach(a => {
// To Iterate over each key in the element object
Object.keys(a).forEach(k => {
// to print the value of the 'k' key
console.log(k + ' : ' + a[k]);
})
})
1) You can use flatMap and Object.keys to get keys from an array of objects.
let arr = [{ John: 0 }, { Doe: 50 }, { Marry: 100 }];
const result = arr.flatMap((o) => Object.keys(o));
console.log(result);
2) To find all values in an array
let arr = [{ John: 0 }, { Doe: 50 }, { Marry: 100 }];
const values = arr.flatMap((o) => Object.values(o));
console.log(values);
3) If you want to find out all keys and values in an object
let arr = [{ John: 0 }, { Doe: 50 }, { Marry: 100 }];
const result = {
keys: [],
values: [],
};
for (let obj of arr) {
Object.entries(obj).map(([k, v]) => {
result.keys.push(k);
result.values.push(v);
});
}
console.log(result);
If you want to collect all the keys and values of a nested array of objects, you can use Array.prototype.reduce and then collect the keys and values of the nested objects in separate nested arrays, using Object.keys() and Object.values() respectively:
const arr = [{'John': 0}, {'Doe': 50}, {'Marry': 100}];
const allKeysAndValues = arr.reduce((acc, cur) => {
acc.keys.push(...Object.keys(cur));
acc.values.push(...Object.values(cur));
return acc;
}, { keys: [], values: [] });
console.log(allKeysAndValues);
A one liner could be
let arr = [{'John': 0}, {'Doe': 50}, {'Marry': 100}]
console.log( arr.map( obj => Object.entries(obj)));
I am using Axios to execute a GET request to a public API, I need to combine the names if they are the same and add the values up to only show the top 20 (It's a large dataset) based on the highest to lowest amounts(ascending order).
Axios Response
[
{
name: "foo1",
value: "8123.30"
},
{
name: "foo1",
value: "2852.13"
},
{
name: "foo2",
value: "5132.23"
},
{
name: "foo1",
value: "1224.20"
},
{
name: "foo2",
value: "1285.23"
}
1200...
];
Expected Output
[
{ name: "foo1",
value: "12199.63" // from all combined "foo1" amounts in the dataset
},
{
name: "foo2",
value: "6417.46" // from all combined "foo2" amounts in the dataset
},
18..
]
I tried to do something like this....
const fetchData = () => {
return axios.get(url)
.then((response) => response.data)
};
function onlyWhatINeed() {
const newArr = []
return fetchData().then(data => {
const sortedData = data.sort((a, b) => parseFloat(a.value) - parseFloat(b.value));
// I need to loop through the dataset and add all the "values" up
// returning only the top 20 highest values in an array of those objects
newArr.push(sortedData)
})
}
But I am confused as to how to push this data to a new array of the sorted data (top 20 values in ascending order) and use this data in my web application. I am a bit new to creating REST APIs so if you could provide articles and/or resources so I can understand a little more that would be an awesome bonus!
You can combine the entries that share the same name using a map, then sort the map and keep the first twenty elements :
function onlyWhatINeed() {
const newArr = []
return fetchData().then(data => {
let map = new Map();
data.forEach(d => {
if(!map.has(d.name)) {
map.set(d.name, parseFloat(d.value));
} else {
map.set(d.name, map.get(d.name) + parseFloat(d.value));
}
})
return Array.from(map.entries()).sort((a, b) => a.value - b.value).slice(0, 20);
})
}
Since you're dealing with a large dataset, I recommend that you handle this server side instead of offloading the sorting to your clients.
async function fetchData(){
const { data } = await axios.get(url);
let newArr = []
data.forEach((e,i) => {
let index = newArr.findIndex(el => el.name === e.name);
if(index !== -1 ) newArr[index].value += parseFloat(e.value); //add to the value if an element is not unique
if(index === -1 ) newArr.push({...e, value: parseFloat(e.value)}); //push to the array if the element is unique and convert value to float
});
return newArr.sort((a,b) => a.value - b.value).slice(0,20);//returns an array of 20 elements after sorting
}
Please do more research on how to work with arrays and objects in general.
If you happen to already be using lodash, then here's a functional-style solution using lodash chaining. Probably not optimal performance, but could be useful for relatively small datasets.
const _ = require('lodash');
const data = [
{
name: "foo1",
value: "8123.30"
},
{
name: "foo1",
value: "2852.13"
},
{
name: "foo2",
value: "5132.23"
},
{
name: "foo1",
value: "1224.20"
},
{
name: "foo2",
value: "1285.23"
},
{
name: "foo3",
value: "1000.00"
},
{
name: "foo3",
value: "2000.00"
}
];
// 1. convert string values to floats
// 2. group by name
// 3. sum values by name
// 4. sort by descending value
// 5. take top 20
const output =
_(data)
.map(obj => ({
name: obj.name,
value: parseFloat(obj.value)
}))
.groupBy('name')
.map((objs, key) => ({
name: key,
value: _.sumBy(objs, 'value')
}))
.orderBy(['value'], 'desc')
.slice(0, 20)
.value();
console.log('output:', output);
I currently have an array of simple objects:
data = [{ "alternative hip hop": 3 }, { "escape room": 4 }, ...]
...to which I'd like to transform into
newData = [
{ "name": "alternative hip hop", "count": 3 },
{ "name": "escape room", "count" 4 }
]
Is this doable with a map? I've failed at figuring out how to do so with one.
lodash responses are welcome as well
Assuming each item in the data has a single key/value pair, you'd want:
data.map(obj => {
const key = Object.keys(obj)[0]; //Just get the first key we find
return {
name: key,
count: obj[key]
};
})
I hope I didn't write it false on my Mobile, but here is a way:
let newData = data.map(e => {
for(let key in e) {
return {
name: key,
count: e[key]
};
}
});
Im not familiar with loadsh, but with javascript you can do the following:
var data = [{ "alternative hip hop": 3 }, { "escape room": 4 }]
var newData = [];
data.forEach((item)=>{ //loop over the array
Object.keys(item) //get the object keys
.map((keyName)=>{ //loop over each key
newData.push({name:keyName, count:item[keyName]}) //insert it into the new array
})
})
console.log(newData)
I have the following two objects
var productionTime= [
{Rob3: 20},
{Rob8: 100},
{Rob4: 500},
{Rob1: 100},
{Rob5: 500}
];
var Busytime= [
{Rob4: 10},
{Rob3: 200},
{Rob8: 100},
{Rob5: 200},
{Rob1: 100}
];
Now I want to divide each item in 'productionTime' by its respective 'BusyTime' which have the same key.
For example productionTime.Rob3 should be divided by BusyTime.Rob3 and productionTime.Rob8 should be divided by BusyTime.Rob8 and so on.
How can I do this with array.find() or array.filter() in javascript/nodejs?
P.S: I know i can do it by using two nested forEach loops but that is I guess very slow
You could use a hash table and a single loop for every array.
var productionTime = [{ Rob3: 20 }, { Rob8: 100 }, { Rob4: 500 }, { Rob1: 100 }, { Rob5: 500 }];
busytime = [{ Rob4: 10 }, { Rob3: 200 }, { Rob8: 100 }, { Rob5: 200 }, { Rob1: 100 }],
hash = Object.create(null);
busytime.forEach(function (o) {
var key = Object.keys(o)[0];
hash[key] = o[key];
});
productionTime.forEach(function (o) {
var key = Object.keys(o)[0];
o[key] /= hash[key];
});
console.log(productionTime);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Convert both arrays to object using Object#assign and the spread syntax. Get the keys from one of them using Object#keys, and iterate the keys using Array#map. Create a new object for each key using shorthand property names:
const productionTime = [{"Rob3":20},{"Rob8":100},{"Rob4":500},{"Rob1":100},{"Rob5":500}];
const Busytime= [{"Rob4":10},{"Rob3":200},{"Rob8":100},{"Rob5":200},{"Rob1":100}];
// create objects from both arrays
const productionTimeObj = Object.assign({}, ...productionTime);
const busytimeObj = Object.assign({}, ...Busytime);
// get the keys from one of the objects, and iterate with map
const result = Object.keys(productionTimeObj).map((key) => ({
// create a new object with the key, and the result of the division
[key]: productionTimeObj[key] / busytimeObj[key]
}));
console.log(result);