Reduce Object Array to Single Object [duplicate] - javascript

I've read this answer on SO to try and understand where I'm going wrong, but not quite getting there.
I have this function :
get() {
var result = {};
this.filters.forEach(filter => result[filter.name] = filter.value);
return result;
}
It turns this :
[
{ name: "Some", value: "20160608" }
]
To this :
{ Some: "20160608" }
And I thought, that is exactly what reduce is for, I have an array, and I want one single value at the end of it.
So I thought this :
this.filters.reduce((result, filter) => {
result[filter.name] = filter.value;
return result;
});
But that doesn't produce the correct result.
1) Can I use Reduce here?
2) Why does it not produce the correct result.
From my understanding, the first iteration the result would be an empty object of some description, but it is the array itself.
So how would you go about redefining that on the first iteration - these thoughts provoke the feeling that it isn't right in this situation!

Set initial value as object
this.filters = this.filters.reduce((result, filter) => {
result[filter.name] = filter.value;
return result;
},{});
//-^----------- here
var filters = [{
name: "Some",
value: "20160608"
}];
filters = filters.reduce((result, filter) => {
result[filter.name] = filter.value;
return result;
}, {});
console.log(filters);
var filters = [{
name: "Some",
value: "20160608"
}];
filters = filters.reduce((result, {name, value}= filter) => (result[name] = value, result), {});
console.log(filters);

Since 2019 (ES2019) you can go with Object.fromEntries() but you need to map to array first.
const filtersObject = Object.fromEntries(filters.map(({ name, value }) => [name, value])

Related

Javascript turn a flat array into a nested object of keys with a value [duplicate]

Let's say I have the following array:
['product' , 'model', 'version']
And I would like to have an object such as:
{
product: {
model: {
version: {
}
}
}
}
However, that array is dynamic so it could have 2, 3 or fewer more items.
How can this be achieved in the most efficient way?
Thanks
Just turn it inside out and successively wrap an inner object into an outer object:
const keys = ['product', 'model', 'version'];
const result = keys.reverse().reduce((res, key) => ({[key]: res}), {});
// innermost value to start with ^^
console.log(result);
You can also do it with Array.prototype.reduceRight:
const result = ['product','model','version'].reduceRight((all, item) => ({[item]: all}), {});
console.log(result);
If I understood request correctly, this code might do what you need:
function convert(namesArray) {
let result = {};
let nestedObj = result;
namesArray.forEach(name => {
nestedObj[name] = {};
nestedObj = nestedObj[name];
});
return result;
}
console.log(convert(['a', 'b', 'c']));

How to sort array of objects by dynamic proprety name?

I would appreciate your help or idea how to sort array of object in ascending order by first value.
This is array
[{"0":"yanni"},
{"1150":"finally"},
{"852":"discovered"},
{"59":"what"},
{"30064":"had"},
{"397":"really"},
{"3100":"happened"},
{"3":"to"},
{"0":"skura"},
{"7523":"lets"},
{"6550":"try"},
]
and I want to be sorted by first number like:
[{"0":"yanni"},
{"0":"skura"},
{"3":"to"},
{"59":"what"},
.....
]
I tried like this
const keys = Object.keys(sentenceFreq);
console.log("key",keys)
const valuesIndex = keys.map((key) => ({key, value: sentenceFreq[key]}));
valuesIndex.sort((a, b) => b.value - a.value); // reverse sort
const newObject = {};
for (const item of valuesIndex) {
newObject[item.key] = item.value;
}
console.log("test", newObject);
but they are sorted only by key values...
Any help is appericated.
Thank you!
Use sort. Grab the first element of the Object.keys of both a and b and coerce them to an integer, then return the new sort order.
const arr = [{"0":"yanni"},{"1150":"finally"},{"852":"discovered"},{"59":"what"},{"30064":"had"},{"397":"really"},{"3100":"happened"},{"3":"to"},{"0":"skura"},{"7523":"lets"},{"6550":"try"}];
arr.sort((a, b) => {
const first = +Object.keys(a)[0];
const second = +Object.keys(b)[0];
return first - second;
});
console.log(arr);
By default, the sort method sorts elements alphabetically. but in your case, you can get the keys and try sort numerically just add a new method that handles numeric sorts (shown below) -
let arr = [{
"0": "yanni"
}, {
"1150": "finally"
}, {
"852": "discovered"
}, {
"59": "what"
}, {
"30064": "had"
}, {
"397": "really"
}, {
"3100": "happened"
}, {
"3": "to"
}, {
"0": "skura"
}, {
"7523": "lets"
}, {
"6550": "try"
}];
arr.sort(function(a, b) {
const first = +Object.keys(a)[0];
const second = +Object.keys(b)[0];
return first - second
});
console.log(arr);

How to solve "Expected to return a value in arrow function" error in eslint

I am using eslint and getting this error.
Expected to return a value in arrow function
The error is showing on the third line of the code.
useEffect(() => {
let initialPrices = {};
data.map(({ category, options }) => {
initialPrices = {
...initialPrices,
[category]: options[0].price,
};
});
setSelectedPrice(initialPrices);
}, []);
The map function must return a value. If you want to create a new object based on an array you should use the reduce function instead.
const reducer = (accumulator, { category, options }) => (
{...accumulator, [category]:options[0].price}
)
const modifiedData = data.reduce(reducer)
More information https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
The map function is intended to be used when you want to apply some function over every element of the calling array. I think here it's better to use a forEach:
useEffect(() => {
let initialPrices = {};
data.forEach(({ category, options }) => {
initialPrices = {
...initialPrices,
[category]: options[0].price,
};
});
setSelectedPrice(initialPrices);
}, []);
Your map function should return something. Here it's not the case so the error happens. Maybe a reduce function will be more appropriate than map?
From what I can see in your case, is that you want to populate initialPrices, and after that to pass it setSelectedPrice. The map method is not a solution, for you in this case, because this method returns an array.
A safe bet in your case would a for in loop, a forEach, or a reduce function.
const data = [
{
category: "ball",
options: [
{
price: "120.45"
}
]
},
{
category: "t-shirt",
options: [
{
price: "12.45"
}
]
}
];
The forEach example:
let initialPrices = {};
// category and options are destructured from the first parameter of the method
data.forEach(({ category, options}) => {
initialPrices[category] = options[0].price;
});
// in this process I'm using the Clojure concept to add dynamically the properties
setSelectedPrice(initialPrices);
The reduce example:
const initialPrices = Object.values(data).reduce((accumulatorObj, { category, options}) => {
accumulatorObj[category] = options[0].price
return accumulatorObj;
}, {});
setSelectedPrice(initialPrices);

Convert array into nested object

Let's say I have the following array:
['product' , 'model', 'version']
And I would like to have an object such as:
{
product: {
model: {
version: {
}
}
}
}
However, that array is dynamic so it could have 2, 3 or fewer more items.
How can this be achieved in the most efficient way?
Thanks
Just turn it inside out and successively wrap an inner object into an outer object:
const keys = ['product', 'model', 'version'];
const result = keys.reverse().reduce((res, key) => ({[key]: res}), {});
// innermost value to start with ^^
console.log(result);
You can also do it with Array.prototype.reduceRight:
const result = ['product','model','version'].reduceRight((all, item) => ({[item]: all}), {});
console.log(result);
If I understood request correctly, this code might do what you need:
function convert(namesArray) {
let result = {};
let nestedObj = result;
namesArray.forEach(name => {
nestedObj[name] = {};
nestedObj = nestedObj[name];
});
return result;
}
console.log(convert(['a', 'b', 'c']));

Javascript Reduce Challenge, Getting the value of an Obj's Key

I'm following a course online and one of the challenges is this:
Write a function called extractKey which accepts two parameters, an array of objects, and the name of a key and returns an array with just the values for that key: You must use reduce.
extractKey([{name: "Elie", isInstructor:true},{name: "Tim", isInstructor:true},{name: "Matt", isInstructor:true}], "name");
// ["Elie", "Tim", "Matt"]
I thought I could do something like this:
function extractKey(arr, key) {
arr.reduce(function(a, b) {
console.log(a.push(b[key]))
}, [])
}
But its returning 1. I have a general idea of pushing each value into the empty array, but when console logging each value, a will return undefined at the next accumulator.
If you have to use reduce then I'd combine it with concat like this.
var arr = [{
name: "Elie",
isInstructor: true
}, {
name: "Tim",
isInstructor: true
}, {
name: "Matt",
isInstructor: true
}]
function extractKeys(array, key) {
return array.reduce((acc, obj) => {
return acc.concat(obj[key])
}, [])
}
console.log(extractKeys(arr, 'name'))
If you use reduce (not really neccessary here), you need to pass on the accumulator:
function extractKey(arr, key) {
arr.reduce(function(acc, el) {
console.log(a.push(el[key]))
return acc; // <--
}, [])
}
Alternatively a good old for loop might be easier to understand:
function extractKey(arr, key){
const result = [];
for(const el of arr)
result.push(el[key]);
return result;
}
Finally you also might use map instead and currying to beautify it:
const extract = key => obj => obj[key];
const result = original.map(extract("name"));
you were very close but with reduce you have to return the value after every iteration of your callback since only the accumulator's value is saved
function extractKey(arr, key) {
arr.reduce(function(a, b) {
a.push(b[key])
console.log(a)
return a;
}, []);
}

Categories