Transform complex object into key value - javascript

I have an array
const arr = [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"rank": 1,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:21.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
},
{
"id": 2,
"name": "Litecoin",
"symbol": "LTC",
"slug": "litecoin",
"rank": 20,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:22.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
}
]
And I want to transform the array to this
{
"BTC": "Bitcoin",
"LTC": "Litecoin",
}
Is there a better way than this?
const result = {}
arr.reduce((accum, val) => {
Object.assign(result, { [val.symbol]: val.name });
}, {})
console.log(result)

Use Object.entries() an each object which will return them as an array of arrays -- each sub-array will be a key/value pair ([key, value]) then use Object.assign() to create a new object ({[key]: value}) to return. Then flatten it so they are all in one array.
const arr=[{id:1,name:"Bitcoin",symbol:"BTC",slug:"bitcoin",rank:1,is_active:1,first_historical_data:"2013-04-28T18:47:21.000Z",last_historical_data:"2022-02-18T11:39:00.000Z",platform:null},{id:2,name:"Litecoin",symbol:"LTC",slug:"litecoin",rank:20,is_active:1,first_historical_data:"2013-04-28T18:47:22.000Z",last_historical_data:"2022-02-18T11:39:00.000Z",platform:null}];
const conv = array => {
let objects = array.map(obj => Object.entries(obj).map(([key, val]) => Object.assign({}, {[key]: val})));
return objects.flat();
};
console.log(conv(arr));

let arr = [
{
"id": 1,
"name": "Bitcoin",
"symbol": "BTC",
"slug": "bitcoin",
"rank": 1,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:21.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
},
{
"id": 2,
"name": "Litecoin",
"symbol": "LTC",
"slug": "litecoin",
"rank": 20,
"is_active": 1,
"first_historical_data": "2013-04-28T18:47:22.000Z",
"last_historical_data": "2022-02-18T11:39:00.000Z",
"platform": null
}
]
// As suggested, here it is without having to create an initial array
let alternativeArray = arr.map((val) => {
return {[val.symbol]: val.slug}
})
console.log(alternativeArray)
Here is the answer to why the object key is being set in that format:
Javascript set object key by variable

The answer is
Object.fromEntries(arr.map(({symbol, name}) => [symbol, name]))

Related

Modify and Combine Array of Objects by ID

I have the following array of objects:
[
{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
I need to restructure it, so it combines the objects by ID, and creates a new nested array of objects:
[
{
"id": 1,
"prices": [
{
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
]
}
{
"id": 2,
"prices": [
{
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
}
]
Is there a simple way to do this? I'm getting lost in split, forEach and maps. Thanks.
One way is to use a Map to collect the prices per id. First associate an empty prices list for each id, then iterate the data to populate those arrays, and finally extract the Map values to get the result:
const data = [{"id": 1,"price": 22,"from": "00:00:00","to": "02:00:00"},{"id": 1,"price": 23,"from": "02:00:00","to": "04:00:00"},{"id": 2,"price": 10,"from": "04:00:00","to": "1.00:00:00"}];
const map = new Map(data.map(({id}) => [id, { id, prices: [] }]));
for (const {id, ...rest} of data) map.get(id).prices.push(rest);
const result = [...map.values()];
console.log(result);
Grouping by hash can save you from calling .find() or .findIndex()
const data=[{id:1,price:22,from:"00:00:00",to:"02:00:00"},{id:1,price:23,from:"02:00:00",to:"04:00:00"},{id:2,price:10,from:"04:00:00",to:"1.00:00:00"}];
const result = Object.values(data.reduce((acc, { id, ...rest }) => {
acc[id] ??= { id, prices: [] };
acc[id].prices.push(rest);
return acc;
}, {}));
console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
You can use the Array.reduce method with Array.findIndex to convert your data.
const data = [{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
];
const transformedData = data.reduce((acc, item) => {
const priceData = {
price: item.price,
to: item.to,
from: item.from,
};
const index = acc.findIndex(({
id
}) => id === item.id);
if (index === -1) {
return [
...acc,
{
id: item.id,
prices: [
priceData
]
},
];
} else {
acc[index].prices.push(priceData);
return acc;
}
}, []);
console.log(transformedData);
const items = [
{
"id": 1,
"price": 22,
"from": "00:00:00",
"to": "02:00:00"
},
{
"id": 1,
"price": 23,
"from": "02:00:00",
"to": "04:00:00"
},
{
"id": 2,
"price": 10,
"from": "04:00:00",
"to": "1.00:00:00"
}
]
const result = items
.map(i => i.id)
.filter((item, pos, self) => self.indexOf(item) == pos)
.map( i => ({
id : i,
prices : items
.filter(item => item.id === i)
.map(({ price, from, to}) => ({price, from , to}) )
}) )
console.log(result)
Yes, there is an easy way using reduce().
const input = [
{
id: 1,
price: 22,
from: "00:00:00",
to: "02:00:00",
},
{
id: 1,
price: 23,
from: "02:00:00",
to: "04:00:00",
},
{
id: 2,
price: 10,
from: "04:00:00",
to: "1.00:00:00",
},
];
const output = input.reduce((nested, cur) => {
const objWithoutId = (({id, ...o}) => o)(cur);
if (!nested[cur.id]) {
nested[cur.id] = {
id: cur.id,
prices: [objWithoutId]
};
}
else nested[cur.id].prices.push(objWithoutId);
return nested;
}, {});
console.log(Object.values(output));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Explanation
We loop over the input using a JavaScript object. For every object we check it's ID. When we don't have that ID stored in our object already we create a new object containing the id and a prices array as well as the current value (without the id property). If we have encountered the same id already we already just need to push the current value (without the id property) to the already existing array.
Since we only have one loop and the lookups take O(1) time this algorithm takes O(n) to give a valid result.
Using this one-liner
const objWithoutId = (({id, ...o}) => o)(cur);
we create a new object which contains all properties except id.
Lat but not least we just need to get the values of the created JavaScript object using Object.values(). Instead of a JavaScript object you could also use a Map to perform the equivalent algorithm with the same runtime properties.
You can use the Object.entries, Array#reduce and Array#map methods as follows:
const input = [ { "id": 1, "price": 22, "from": "00:00:00", "to": "02:00:00" }, { "id": 1, "price": 23, "from": "02:00:00", "to": "04:00:00" }, { "id": 2, "price": 10, "from": "04:00:00", "to": "1.00:00:00" } ],
output = Object.entries(input.reduce(
(acc, {id,...rest}) =>
({...acc, [id]: [...(acc[id] || []), rest]}), {}
))
.map(([id, prices]) => ({id,prices}));
console.log( output );

Removing duplicate value from list of javascript objects in react js

I have react project and in that have a javascript array of object similar to given below and in that object it has a value called category.
const data = [{
"id": 1,
"item": "760",
"price": "$609.05",
"category": "BMW"
}, {
"id": 2,
"item": "Frontier",
"price": "$317.89",
"category": "Nissan"
}, {
"id": 3,
"item": "Odyssey",
"price": "$603.64",
"category": "BMW"
}]
Im mapping through the list and displaying the category as shown below.
{data.map(item => (<span>{item.category}</span>))}
Here, the category duplicates and display several times when there are several similar items. Considering the given data list, the category BMW display twice.
What I want is, even if there are multiple similar categories, I only want to display once. Is this possible and how can I do it?
You could add your categories into a Set
const data = [{
"id": 1,
"item": "760",
"price": "$609.05",
"category": "BMW"
}, {
"id": 2,
"item": "Frontier",
"price": "$317.89",
"category": "Nissan"
}, {
"id": 3,
"item": "Odyssey",
"price": "$603.64",
"category": "BMW"
}]
let categories = new Set()
data.forEach(entry => {categories.add(entry.category) })
categories.forEach(cat => console.log(cat))
There can be various ways to reach the desired result. I would do it with a Set() and destructuring syntax:
{[...new Set(data.map(item => (<span>{item.category}</span>)))]}
const data = [{
"id": 1,
"item": "760",
"price": "$609.05",
"category": "BMW"
}, {
"id": 2,
"item": "Frontier",
"price": "$317.89",
"category": "Nissan"
}, {
"id": 3,
"item": "Odyssey",
"price": "$603.64",
"category": "BMW"
}]
const newData = [...new Set(data.map(item => ("<span>" + item.category + "</span>")))]
console.log(newData);
you can use {data.find(item => (<span>{item.category}</span>))}. The find() method returns the first element in the provided array that satisfies the provided testing function
You can use the filter
let array= data.filter((v,i,a)=>a.findIndex(v2=>(v2.category===v.category))===i)
and
{array.map(item => (<span>{item.category}</span>))}
const data = [{
"id": 1,
"item": "760",
"price": "$609.05",
"category": "BMW"
}, {
"id": 2,
"item": "Frontier",
"price": "$317.89",
"category": "Nissan"
}, {
"id": 3,
"item": "Odyssey",
"price": "$603.64",
"category": "BMW"
}]
function getUniqueArrayBy(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()]
}
const filtered = getUniqueArrayBy(data, 'category');
console.log(filtered);
Use native methods .reduce and .map of Array in chain.
const categories = data.reduce((acc, {category}) => {
if (!acc.includes(category)) { // check if there's not such value in accumulator
acc.push(category); // adding category
}
return acc; // returning value
}, []) // [] is an accumulator value
.map(category => <span>{category}</span>); // iterating over result
Piece a cake.

JavaScript / typescript: unable to regenerate object

I have an object as specified below:
{
"player settings": [
{
"id": 1,
"labelName": "site language",
"labelValue": [
{
"id": 1,
"languageName": "ARABIC",
"language": "لغتك",
"languageCode": "AE"
},
{
"id": 2,
"languageName": "CHINESE",
"language": "你的语言",
"languageCode": "ZH"
},
],
"dataType": "DD",
"selectedData": "2"
},
{
"id": 2,
"labelName": "subtitle language",
"labelValue": [
{
"id": 1,
"languageName": "ARABIC",
"language": "لغتك",
"languageCode": "AE"
},
{
"id": 2,
"languageName": "CHINESE",
"language": "你的语言",
"languageCode": "ZH"
},
],
"dataType": "DD",
"selectedData": "1"
},
]
},
{
"channel": [
{
"id": 11,
"labelName": "channel label",
"dataType": "TX",
"selectedData": "jhfh"
}
]
},
{
"others": [
{
"id": 16,
"labelName": "others label",
"dataType": "TX",
"selectedData": "dhgdhg"
}
]
}
How can I modify and re-generate the object with the following conditions:
if dataType === 'DD' then convert selectedData into number.
I wrote the below code but stuck here:
for (var j = 0; j < this.myobject.length; j++){
this.myobject.forEach(obj => {
console.log(obj)
});
}
You can use for..in
let data = {"player settings": [{"id": 1,"labelName": "site language","labelValue": [{"id": 1,"languageName": "ARABIC","language": "لغتك","languageCode": "AE"},{"id": 2,"languageName": "CHINESE","language": "你的语言","languageCode":"ZH"},],"dataType": "DD","selectedData": "2"},],"player settings2": [{"id": 1,"labelName": "site language","labelValue": [{"id": 1,"languageName": "ARABIC","language": "لغتك","languageCode": "AE"},{"id": 2,"languageName": "CHINESE","language": "你的语言","languageCode":"ZH"},],"dataType": "NO DD","selectedData": "2"},]}
for (let key in data) {
data[key].forEach(obj => {
if (obj.dataType === "DD") {
obj.selectedData = +(obj.selectedData || 0)
}
})
}
console.log(data)
Immutable approach
let data = {"player settings": [{"id": 1,"labelName": "site language","labelValue": [{"id": 1,"languageName": "ARABIC","language": "لغتك","languageCode": "AE"},{"id": 2,"languageName": "CHINESE","language": "你的语言","languageCode":"ZH"},],"dataType": "DD","selectedData": "2"},],"player settings2": [{"id": 1,"labelName": "site language","labelValue": [{"id": 1,"languageName": "ARABIC","language": "لغتك","languageCode": "AE"},{"id": 2,"languageName": "CHINESE","language": "你的语言","languageCode":"ZH"},],"dataType": "NO DD","selectedData": "2"},]}
let newObj = {}
for (let key in data) {
newObj[key] = data[key]
data[key].forEach(obj => {
if (obj.dataType === "DD") {
newObj.selectedData = +(obj.selectedData || 0)
}
})
}
console.log(newObj)
We can use filter on the main obj and then proceed modifying the object.
function modifyDataToNumber(){
let myObject = jsonObj['player settings'];
let ddMyObject = myObject.filter((row)=>(row["dataType"]==="DD"));
console.log(ddMyObject[0]["selectedData"]);
ddMyObject.forEach((row,index)=>{
ddMyObject[index]["selectedData"] = +ddMyObject[index]["selectedData"];
})
console.log(jsonObj);
}
modifyDataToNumber();
I would do something like this
const json = {
"player settings": [
{
"id": 1,
"labelName": "site language",
"labelValue": [
{
"id": 1,
"languageName": "ARABIC",
"language": "لغتك",
"languageCode": "AE"
},
{
"id": 2,
"languageName": "CHINESE",
"language": "你的语言",
"languageCode": "ZH"
},
],
"dataType": "DD",
"selectedData": "2"
},
]
};
json['player settings'] = json['player settings'].map(setting => {
if (setting.dataType === 'DD') {
const updatedSetting = {
...setting,
selectedData: parseInt(setting.selectedData)
};
return updatedSetting;
}
return setting;
});
console.log('Result', json);
Since you say "re-generate", I assume you want an immutable approach to this (that is, generate a copy of the data with the desired changes, rather than changing the original object).
To that, you can use spread syntax and Array#map:
let convertSetting = setting => ({
...setting,
selectedData: setting.dataType === "DD"
? parseInt(setting.selectedData)
: setting.selectedData
});
let convert = x => ({
...x,
["player settings"]: x["player settings"].map(convertSetting)
});
Then you can use that function as convert(yourOriginalObject).

Filter an array inside an object inside an array in javascript

I have this object and I need a function to filter the pokemon (whole objects) by type or weaknesses (the user decides).
For example: "the user needs to filter all the fire type pokemon" and the result would be an array containing every fire type pokemon object
var POKEMON = {
"pokemon": [{
"id": 1,
"num": "001",
"name": "Bulbasaur",
"img": "https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png",
"type": [
"Grass",
"Poison"
],
"height": "0.71 m",
"weight": "6.9 kg",
"candy": "Bulbasaur Candy",
"candy_count": 25,
"egg": "2 km",
"spawn_chance": 0.69,
"avg_spawns": 69,
"spawn_time": "20:00",
"multipliers": [1.58],
"weaknesses": [
"Fire",
"Ice",
"Flying",
"Psychic"
],
"next_evolution": [{
"num": "002",
"name": "Ivysaur"
}, {
"num": "003",
"name": "Venusaur"
}]
},{
"id": 2,
"num": "002",
"name": "Ivysaur",
"img": "https://assets.pokemon.com/assets/cms2/img/pokedex/full/002.png",
"type": [
"Grass",
"Poison"
],
"height": "0.99 m",
"weight": "13.0 kg",
"candy": "Bulbasaur Candy",
"candy_count": 100,
"egg": "Not in Eggs",
"spawn_chance": 0.042,
"avg_spawns": 4.2,
"spawn_time": "07:00",
"multipliers": [
1.2,
1.6
],
"weaknesses": [
"Fire",
"Ice",
"Flying",
"Psychic"
],
"prev_evolution": [{
"num": "001",
"name": "Bulbasaur"
}],
"next_evolution": [{
"num": "003",
"name": "Venusaur"
}]
},
... (+149 other pokemon)
I already have a function and it works but I'd rather not use for loops:
const filterPokemon = (data, whatToFilter, valueToCompare) => {
return data.filter(pokemon => {
for(let i = 0 ; i < pokemon[whatToFilter].length ; i++){
if(pokemon[whatToFilter][i] === valueToCompare){
return pokemon;
}
}
});
};
filterPokemon(POKEMON.pokemon, "type", "Fire");
Use .includes instead to see if any items in the pokemon[whatToFilter] array equal the valueToCompare:
const filterPokemon = (data, whatToFilter, valueToCompare) => {
return data.filter(creatureObj => (
creatureObj[whatToFilter].includes(valueToCompare)
));
};
Side note, might be a bit opinion-based, but you might consider changing the variable name from pokemon (eg here I used "creatureObj") because "pokemon" can be either singular or plural, so it isn't entirely clear what sort of object it is.
Could also avoid that entirely by destructuring the parameter, if you wanted:
const filterPokemon = (data, whatToFilter, valueToCompare) => {
return data.filter(({ [whatToFilter]: arr }) => (
arr.includes(valueToCompare)
));
};
You have the first part right, but just use the array find() operator to filter, or since these are simple primitive arrays, you could just use .indexOf(value) > -1 or .includes() or a few other operators. I prefer find because it works on complex types as well.
const filterPokemon = (pokemonList, propToFilter, value) => {
return pokemonList.filter(pokemon => {
return pokemon[propToFilter].find(p => p === value);
});
};
Another option is to use Array.some() inside the filter function.
const filterPokemon = (data, whatToFilter, valueToCompare) =>
{
return data.filter(pokemon => pokemon[whatToFilter].some(x => x === valueToCompare));
}
Example:
var POKEMON = {
"pokemon": [{
"id": 1,
"num": "001",
"name": "Bulbasaur",
"img": "https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png",
"type": [
"Grass",
"Poison"
]
},
{
"id": 2,
"num": "002",
"name": "Ivysaur",
"img": "https://assets.pokemon.com/assets/cms2/img/pokedex/full/002.png",
"type": [
"Grass",
"Poison",
"Fire"
],
}
]};
const filterPokemon = (data, whatToFilter, valueToCompare) =>
{
return data.filter(pokemon => pokemon[whatToFilter].some(x => x === valueToCompare));
}
let res = filterPokemon(POKEMON.pokemon, "type", "Fire");
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Add Extra Key value on existing object under loop

I have a data set like this:
[
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
},
]
Now For getting the value one by one I have created a loop. Under loop I am getting the value.
Now if I want to add extra key value on that object then how it will be done.?
I tried data[i].extrakey = "value";
console.log(data);
but it will not set.
Any help is really appreciated
Use map
array = array.map( s => Object.assign( s, {extrakey : "value" } ) );
You can use spread along with array.prototype.map to add the extra key:
var arr = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
},
];
var result = arr.map(e => ({...e, extraKey: 'value'}));
console.log(result);
You can see it in the example below. Just iterating over the array and adding a new key will alter the objects inside the array, because object is a reference type and you are just working with a reference which changes the original object.
const array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
array.forEach(item => item.extraKey = 'value');
console.log(array);
Also if you want to change the array items, it will be better to not change the original objects, but create their copies and provide a new array.
const array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
const newArray = array.map(item => Object.assign({}, item, { extraKey: 'value' }));
console.log(newArray);
var array = [
{
"_id": "5aa7b6add9655d0bd4ce1f53",
"user_name": "as",
"createdate": "2018-03-13T11:31:57.133Z",
},
{
"_id": "5aa7b6add9655d0bd4ce1f54",
"user_name": "ds",
"createdate": "2018-03-13T11:31:57.133Z",
}
];
array = array.map( s => Object.assign( s, {extrakey : "value" } ) );

Categories

Resources