I have
const menu = ['home', 'news', 'about'];
I want to map it to this:
let menuExt =
{
home: Common.locs['home'],
news: Common.locs['news'],
about: Common.locs['about']
};
How do I do that? I tried
let menuExt = menu.map(item => {
return {
item: Common.locs[item]
}
});
but I got an array with "item" as property, but I want one object with properties home, news, about... (there are many more but I shortened it here)
menu.map(item => {menuExt[item]=Common.locs[item]});
I managed this way, but I don't know if there is a cleaner and faster solution maybe:
let menuExt = {}
menu.forEach((item) => {
menuExt[item] = Common.locs[item]
});
The idiomatic way would be to use Array.reduce, because you're taking an array of objects and returning a single object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
const menu = ['home', 'news', 'about'];
const menuExt = menu.reduce((acc, key) => {
acc[key] = Common.locs[key];
return acc;
}, {});
Related
Suppose there is an array like this:
const a = [ {p:1}, {p:2}, {p:3} ];
Is it possible to destructure this array in order to obtain p = [1, 2, 3] ?
Because this does not work :
const [ ...{ p } ] = a; // no error, same as const p = a.p;
// p = undefined;
Edit
In response to all the answers saying that I need to use Array.prototype.map, I am aware of this. I was simply wondering if there was a way to map during the destructuring process, and the answer is : no, I need to destructure the array itself, then use map as a separate step.
For example:
const data = {
id: 123,
name: 'John',
attributes: [{ id:300, label:'attrA' }, { id:301, label:'attrB' }]
};
function format(data) {
const { id, name, attributes } = data;
const attr = attributes.map(({ label }) => label);
return { id, name, attr };
}
console.log( format(data) };
// { id:123, name:'John', attr:['attrA', 'attrB'] }
I was simply wondering if there was a way, directly during destructuring, without using map (and, respectfully, without the bloated lodash library), to retrive all label properties into an array of strings.
Honestly I think that what you are looking for doesn't exist, normally you would map the array to create a new array using values from properties. In this specific case it would be like this
const p = a.map(element => element.p)
Of course, there are some packages that have many utilities to help, like Lodash's map function with the 'property' iteratee
you can destructure the first item like this :
const [{ p }] = a;
but for getting all values you need to use .map
and the simplest way might be this :
const val = a.map(({p}) => p)
Here's a generalized solution that groups all properties into arrays, letting you destructure any property:
const group = (array) => array.reduce((acc,obj) => {
for(let [key,val] of Object.entries(obj)){
acc[key] ||= [];
acc[key].push(val)
}
return acc
}, {})
const ar = [ {p:1}, {p:2}, {p:3} ];
const {p} = group(ar)
console.log(p)
const ar2 = [{a:2,b:1},{a:5,b:4}, {c:1}]
const {a,b,c} = group(ar2)
console.log(a,b,c)
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);
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])
I'm trying to create a conditional sub-set of an array.
I have an array allBooks which has properties such as type,author,id etc.
In a particular view I want to show only some of properties based on a condition.
For example; displaying summarized properties of all the books in stock.
Here is what I have tried:
let booksInStock: any[] = [];
this.allBooks.forEach(book => {
// Add only when book is in stock
if (book.isInStock) {
// Get only few keys from all the available keys
let temp: any = {
typeOfBook: book.targetType,
author: book.author,
bookId: book.id,
bookDisplayName: book.value,
bookName: book.bookName
};
// Add to the summarized or filtered list
booksInStock.push(temp);
}
});
Is there a more efficient way of doing it?
Using filter and map would be more semantic, like so:
let booksInStock = this.allBooks
.filter(book => book.isInStock)
.map(book => ({
typeOfBook: book.targetType,
author: book.author,
bookId: book.id,
bookDisplayName: book.value,
bookName: book.bookName
})
);
If efficiency is your priority however, a for loop is faster. See this link for an example: https://jsperf.com/map-vs-for-loop-performance/6
For example:
// This function is pretty generic, you can find one in e.g. underscore.js or Ramda:
const pluck = fields => item =>
Object
.keys(item)
.filter(key => fields.includes(key))
.reduce((result, key) => {
result[key] = item[key]
return result
}, {})
// Create filter+map+pluck -settings for different 'views':
const inStock = books =>
books.filter(b => b.isInStock)
.map(pluck(['targetType', 'author', 'id', 'value', 'name']))
// Invoke them:
const booksInStock = inStock([
{ isInStock: true, author:'harry', otherFIeld:'not-included' },
{ isInStock:false, author:'notharry'}
])
I have a dictionary named CarValues in my code which contains following data:
CarValues is a dictionary initialized in the state.
dictionary: CarValues
key ==> string
Value ==> Array
key => Honda, Value => white, yellow, red, orange
key => Toyota, Value => white, yellow, green, black
Key => Volkswagen Value => 123, 456, 343
I would like to delete Honda and its value completely from CarValues. Though, I see few similar questions, I couldn't find the best solution for this question.
How can I remove an attribute from a Reactjs component's state object
This should solve your issue
yourMethod(key) {
const copyCarValues= {...this.state.CarValues}
delete copyCarValues[key]
this.setState({
CarValues: copyCarValues,
})
}
I believe in order to truly do this without mutating the state, you will need to re-create the entire state like so.
class Test extends React.Component {
state = {
thingToDelete: {},
otherStuff: {}
};
deleteThingToDelete = () => {
const {thingToDelete, ...state} = this.state;
this.setState(state);
}
}
Using the spread operator, we achieve a shallow clone, so be wary about that. The other option is to use Object.assign but that will also only offer a shallow clone but you will achieve much better browser support.
Probably arriving here a bit late, but here is a way of doing this with hooks and without actually mutating the previous state.
const sampleItems = {
'key1': { id: 1, name: 'test'},
'key2': { id: 2, name: 'test2'},
}
const Test = props => {
const [items, setItems] = useState(sampleItems);
deleteItemFromStateObject = itemKey => {
setItems(({[itemKey]: toDelete, ...rest}) => rest);
}
}
The easiest way to do this would be:
const carValues = Object.assign({}, this.state.carValues)
delete carValues[key]
this.setState({ carValues })
You can use Underscore.js or Lodash http://underscorejs.org/#omit
_.omit(copyCarValues, 'Honda');
First Initialise Array Globally
var dict = []
Add Object into Dictionary
dict.push(
{ key: "One",value: false},
{ key: "Two",value: false},
{ key: "Three",value: false});
Output :
[0: {key: "One", value: false},
1: {key: "Two", value: false},
2: {key: "Three", value: false}]
Update Object from Dictionary
Object.keys(dict).map((index) => {
if (index == 1){
dict[index].value = true
}
});
Output :
[0: {key: "One", value: false},
1: {key: "Two", value: true},
2: {key: "Three", value: false}]
Delete Object from Dictionary
Object.keys(dict).map((index) => {
if (index == 2){
dict.splice(index)
}
});
Output :
[0: {key: "One", value: false},
1: {key: "Two", value: true}]
Here is another simple enough solution to achieve this.
const myCarsValueInState = this.state.myCarsValueInState;
Object.keys(myCarsValueInState).map((index) => {
myCarsValueInState[index] = undefined; // you can update on any condition if you like, this line will update all dictionary object values.
return myCarsValueInState;
});
Simple enough.