Return Object from map() function not Array - javascript

Sorry if the title is misleading I'm not sure how to accurately describe what I am looking for.
I have an array result which I want to turn into multiple objects where each objects property is the field Name Test I need to keep my result.map method as I use it to merge result with data
result = [{
"Name Test": "Yellow",
Count: 124,
},
{
"Name Test": "Black",
Count: 124,
},
{
"Name Test": "Blue",
Count: 124,
}
];
data = [{
"Name Test": "Yellow",
pop: 1
},
{
"Name Test": "Black",
pop: 1
},
{
"Name Test": "Blue",
pop: 1
}
];
result = result.map((obj1, index) => {
const obj2 = data[index];
return {
[obj1["Name Test"].toUpperCase()]: {
Count: obj1.Count,
pop: obj2.pop,
}
};
});
console.log(JSON.stringify(result))
This code returns an array of objects which is not what I want as I need to be able to use result["YELLOW"] later in my code. I therefore need the result to be in this format, with no arrays.
{
"YELLOW":{
"Count":124,
"pop":1
},
"BLACK":{
"Count":124,
"pop":1
},
"BLUE":{
"Count":124,
"pop":1
}
}
I hope this makes sense and I feel I am very close to what I want and just am missing something small, but every way I have tried to make this work turns into a syntax error.

map() will always return an array.
You should use reduce() and set accumulator to empty object {}
Use the destructuring and spread syntax to isolate Name Test and other properties.
Set the property of accumulator whose key is "Name Test" property of each object and its value is rest of the object.
const arr = [{ "Name Test": "Yellow", Count: 124, pop: 1 }, { "Name Test": "Black", Count: 124, pop: 1 }, { "Name Test": "Blue", Count: 124, pop: 1 } ];
const res = arr.reduce((ac,{["Name Test"]:x,...rest}) => (ac[x] = rest,ac),{})
console.log(res)

map will create a new array. So you can use reduce and pass an empty object in the accumulator
let result = [{
"Name Test": "Yellow",
Count: 124,
pop: 1
},
{
"Name Test": "Black",
Count: 124,
pop: 1
},
{
"Name Test": "Blue",
Count: 124,
pop: 1
}
];
let newResult = result.reduce(function(acc, curr) {
// acc is accumulator which is the required object.
// this will create a nee key in accumulator and will set its value
acc[curr['Name Test'].toUpperCase()] = {
Count: curr.Count,
pop: curr.pop
}
return acc;
}, {}) // {} is accumulator object. This will hold the required keys and values
console.log(newResult)

It's not available in MS browsers yet, (I think), but fromEntries() is pretty nice for this. You can pass it an iterable or key.value pairs, such as the results from map().
let result = [{"Name Test": "Yellow",Count: 124,pop: 1},{"Name Test": "Black",Count: 124,pop: 1},{"Name Test": "Blue",Count: 124,pop: 1}];
let data = [{"Name Test": "Yellow",pop: 1},{"Name Test": "Black",pop: 1},{"Name Test": "Blue",pop: 1}];
let o = Object.fromEntries(result.map(({'Name Test':n, ...o}) => ([n, o])))
let d = Object.fromEntries(result.map(({'Name Test':n, ...o}) => ([n, o])))
console.log(Object.assign(o, d))

Related

destructing array containing objects

let chosen = 4;
let team = [
{ titel: "ahmad", age: 20, available: true, skills: ["html", "css"] },
{ titel: "mizo", age: 30, available: false, skills: ["js", "react"] },
{ titel: "jo", age: 40, available: true, skills: ["pyhton", "django"] },
];
(() => {
if (chosen === chosen) {
let {
titel,
age,
available,
skills: [s1, s2],
} = team[chosen - 1];
console.log(`Team-${chosen}:
name: ${titel}
age: ${age}
skill: ${s1}
availability: ${(() => {
if (available) return `available`;
else return `unavailable`;
})()}
`);
} else return;
})();
why the given code above throws this error
(Uncaught TypeError: Cannot destructure property 'titel' of 'team[(chosen - 1)]' as it is undefined.) in the console if you choose a number less than 1 or greater than 4 ??
This is because it exceed the number of elements in the array.
the team array has 3 items.
To access the first item, whose index is 0, you would do team[0].
To access the last item, whose index is 2, you would do team [2]
When you do team[4-1], you end up with team[3] which has exceeded the length of the array, and is therefore undefined.
Remember, arrays in javascript are 0-indexed. That means the first item is always at index 0, and the last item is at team.length-1, which in this case, is 2.

Using map in a multidimensional array Javascript

I have this set of data that I'm trying to convert to map:
x = [
{
food: 'Steak',
ingredients: [
{
item1: 'pepper',
},
{
item2: "salt",
},
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
This is my current map function, question is how do I iterate on the ingredients?:
<div>
{Object.keys(x).map(key => (
<a key={key}>{x[key].food}</a>
))}
</div>
Something like this?
x = [
{
food: 'Steak',
ingredients: [
{
item1: 'pepper',
},
{
item2: "salt",
},
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
const list = x.map(item =>
({[item.food]: item.ingredients ?
item.ingredients.flatMap(i =>
Object.keys(i).map(k =>
i[k])).join(','): 'no ingredients'}))
console.log(list)
Output:
[
{
"Steak": "pepper,salt"
},
{
"Veggies": "no ingredients"
},
{
"Fruits": "no ingredients"
}
]
A better format for the data:
x = [
{
food: 'Steak',
ingredients: [
"pepper", "salt",
],
},
{
food: 'Veggies'
},
{
food: 'Fruits'
},
];
Naming things is 80% of programming. The other 20% is choosing the right font for your IDE.
If you have an array of objects and the key of object holds no semantic meaning, and there is one key in each object, that's a sign that it should be an array.
You could go one step further:
const ingredients = {
Steak: ["pepper", "salt"],
Veggies: []
Fruits: []
};
The name of the data structure makes sense. It is an "ingredients by food" object.
Where you went off is starting with x as the name of the object. x is an unknown. Start by describing everything clearly, and use JetBrains Mono.
If you want to easily iterate over the object using map (like to render a table in React), then you could do:
const ingredients = [
{Steak: ["pepper", "salt"]},
{Veggies: []},
{Fruits: []}
];
or:
const recipes = [
{food: Steak, ingredients: ["pepper", "salt"]},
{food: Veggies, ingredients: []},
{food: Fruits, ingredients: []}
];
(which is close to the reduction I did to your original data)
That one should be called recipes, which I discovered when I wrote this next function and the names didn't make sense if the object were named ingredients.
recipes.forEach(recipe => {
console.log(`HTML Title: %{recipe.food})
console.log(`HTML Subtitle: Ingredients`)
recipe.ingredients.forEach(ingredient =>
console.log(`* ${ingredient}`)
)
})
See, the names in the data structure make sense, and so do the functions to work with it. And the data structure itself is small and comprehensible. Structure is also data.
JetBrains Mono.
You can store all ingredientItem in one array and then apply Map on that array:
let ingredientItem = [];
x.forEach((item) => {
if (item.ingredients) {
item.ingredients.forEach((ingredient) => {
for (name in ingredient) {
ingredientItem.push(ingredient[name])
}
})
}
})
ingredientItem.map((item) => {
})

Values from last FOR loop over all, after FOR is done

I have a function which get a json as parameter, build another json with some values from given json and return builded json.
function getMyJSON(json) {
var result = {
lastUpdate: "",
legends: null
};
result.legends = (new Array(json.legends.length)).fill({
name: null,
rgb: null,
values: null
});
for (let j = 0; j < json.legends.length; j++) {
result.legends[j].name = json.legends[j].name;
result.legends[j].rgb = json.legends[j].rgb;
result.legends[j].values = (new Array(10)).fill(0);
console.log(result.legends[0].name); //PRINT ONLY FIRST ELEMENT
}
console.log(result.legends);
return result;
}
The problem appear after for loop is done. All result.legends have the same value from the last json.legends
Here is how output look:
The legends.name of first element(result.legends[0].name) is changed after every loop.
At the end, all legends.name from result are equal with the last legends.name from json. Why?
I found on google that it is something about variable scope, but I can't figure it out how to do this.
You need independent objects inside of the array. Array#fill takes the same object reference and this leads to the same result in each object.
Instead of this, you could create a new array with Array.from and map new objects with the second parameter for a callback.
result.legends = Array.from(
{ length: json.legends.length },
_ => ({ name: null, rgb: null, values: null })
);
#NinaScholz has described the problem and solved it, however as I mentioned in the comments on the question you can improve and simplify the logic by using map():
var obj = {
legends: [{
name: 'foo',
rgb: 'C00'
},{
name: 'bar',
rgb: 'FFF'
},{
name: 'fizz',
rgb: 'CCFFCC'
},{
name: 'buzz',
rgb: '000000'
}]
}
console.log(getMyJSON(obj));
function getMyJSON(o) {
return {
lastUpdate: "",
legends: o.legends.map(function(item) {
return {
name: item.name,
rgb: item.rgb,
values: (new Array(10)).fill(0)
}
})
};
}

JSON manipulation - javascript - adding new keys and shifting data

I'm learning to manipulate JSON data and I am stuck trying to figure out how to cajole the following JSON into what I want as shown below:
Any pointers to function/terms/concepts that I should learn for this sort of problem would be greatly appreciated! Thanks
JSON object
{
car: 1,
van: 5,
cat: 99999999999999999999999
}
Desired outcome:
items: [
{ "type": "car", "value": "1"},
{ "type": "van", "value": "5"},
{ "type": "cat", "value": "99999999999999999999999"}
]
You can use a combination of Object.entries and Array.prototype.map:
const obj = { car: 1, van: 5, cat: 99999999999999999999999 };
let list = Object.entries(obj) // [["car",1],["van",5],["cat",99999999999999999999999]]
.map(x => ({ type: x[0], value: x[1] }));
console.log(list);
Or, with some destructuring:
const obj = { car: 1, van: 5, cat: 99999999999999999999999 };
let list = Object.entries(obj)
.map(([type, value]) => ({ type, value }));
console.log(list);
The callback to map:
([type, value]) => ({ type, value })
Expects an array as parameter: [type, value]. The first value in that array is assigned to type, the second one to value.
Then we use a shorthand form to set these values in our returned object:
=> ({ type, value })
I'm a beginner. I tried to solve the problem and this is the best I can come up with, tested in Node.js 10.
const obj = {"car": 1, "van": 5, "cat": 999999}
const items = []
for (let key in obj) {
items.push({"type": key, "value": obj[key]})
}
console.log(items)
One thing I am slightly confused about is the difference between for..in vs for..of, I'm currently looking into it.
Object.keys will return:
['car', 'van', 'cat'];
On this array you can use Array's map function which creates a new array with the results of calling a provided function on every element in the calling array.
var a = {
car: 1,
van: 5,
cat: 99999999999999999999999
}
m = Object.keys(a).map((v)=>{
return {
type: v,
value: a[v]
}
})
console.log(m);
#GustavMahler hope you understand. To learn more about array functions you should look map, reduce and filter.
This one uses object.keys
let js = {car:1, van:5, cat:9999}
Object.keys(js).map( x => ({type: x, value: js[x] }) )
[ { type: 'car', value: 1 },
{ type: 'van', value: 5 },
{ type: 'cat', value: 9999 } ]

How to count items in List with ImmutableJS?

I have a List which looks like this:
["green", "blue","green","green", "blue", "black"]
How can I use the ImmutableJS operators to count these items and get a Map which could look like this:
{ green: {name: green, count: 3}, blue:{name: blue, count: 2}, black:{name: black, count: 1}}
I found the following function here to do just that in plain JS, so how could I achieve this with ImmutableJS?
export const countOccurances = obj => {
return obj
.reduce((counter, x) => {
if (counter.hasOwnProperty(x)) {
counter[x].count = counter[x].count + 1
} else {
counter[x] = {name: x, count: 1}
}
return counter;
}, {})
}
Try groupBy followed by map. Something like this:
list.groupBy(elem => elem).map(arr => {
return {"name" : arr.get(0), "count": arr.size }
})
list.groupBy(elem => elem) will return a KeyedSeq with the color String as it's key and an Iterable of Strings as value. It would look like this in pure JS.
{ green: ["green","green","green"], blue:["blue","blue"], black: ["black"]}
We can then map these to return the size of the iterable as well as the name and we should get what you wanted:
{ green: {name: "green", count: 3}, blue:{name: "blue", count: 2}, black:{name: "black", count: 1}}
Of course if you wanted to get exactly that, you would need to use toJS() at the end.
You could also use a mixed solution:
list.toJS().length

Categories