I am really struggling with the Object transformation. I have an array of Object and want to transform it into Highcharts multi line chart input. I want to get the unique dates first sorted from low to high, which will go into x axis and then transform the Original based on ID and date. The length for each ID.data is going to remain same (for whatever date count is not available for that date it will come as null)
Original:
[
{
"date": "1997-09-29",
"Count": 100,
"ID": "AB12-R"
},
{
"date": "1997-12-30",
"Count": 104.7,
"ID": "AB13-R"
},
{
"date": "1998-03-30",
"Count": 981,
"ID": "BA12-R"
},
{
"date": "1998-06-01",
"Count": 341,
"ID": "BA12-R"
}
]
Transformed:
[{
Identiy : 'AB12-R',
data : [100,null,null,null]
},
{
Identiy : 'AB13-R',
data : [null,104.7,null,null]
},{
Identiy : 'BA12-R',
data : [null,null,981,341]
}]
I have tried with reduce but nothing is working it seems. I am able to group it by ID but not able to handle the null and missing count, Can someone please help me here ?
This is what i have tried:
const result = Original.reduce(function (r, a) {
r[a.ID] = r[a.ID] || [];
r[a.ID].push(a);
return r;
}, Object.create(null));
console.log({'Transformed':result})
Take a look at this solution:
const hcData = [];
data.forEach((d, i) => {
const checkIfExist = hcData.find(data => data.id === d["ID"])
if (checkIfExist) {
checkIfExist.data[i] = d["Count"];
} else {
const initialData = [...Array(data.length)]
initialData.fill(null, 0, data.length)
initialData[i] = d["Count"];
hcData.push({
data: initialData,
id: d["ID"]
})
}
})
Demo: https://jsfiddle.net/BlackLabel/k2dg1wns/
Related
For one of my e-commerce application requirement, I have a nested array of the form (Sample):
const data = [
{
"id": 1,
"group": "upper-wear",
"labels": [
{
"type": "shirts",
"quantity": "20",
},
],
popular: true
},
{
"id": 2,
"group": "bottom-wear",
"lables": [
{
"type": "trousers",
"quantity": "31",
},
],
popular: true
},
]
To this array, I need to insert new objects to the array 'labels' if the group value equals 'upper-wear'.
const newDataToInsert = [
{
"type": 'blazers',
"quantity": 19
},
]
This is what I tried so far, considering that for now I only need to insert to single label (i.e. 'upper-wear') (in future, there can be multiple labels category 'upper-wear', 'bottom-wear', to be inserted into):
const updatedArray = data.map((datum) => {
if (datum.group === 'upper-wear') {
return {
...datum,
labels: [...datum.labels, ...newDataToInsert]
};
}
});
console.log(updatedArray);
But there seems to be a silly issue that I am missing as the result returns like this:
[
{
id: 1,
group: 'upper-wear',
labels: [ [Object], [Object] ],
popular: true
},
undefined
]
I know there may be better approaches available, but this is what I can think of as the minimum solution for now.
any help to resolve the current or any better solution will be highly appreciated.
Try with this
updatedArray = data.map((d) => {
if (d.group && d.group === 'upper-wear') {
return { ...d, labels: d.labels.concat(newDataToInsert) }
} else {
return d;
}
})
const data = [
{
"id": 1,
"group": "upper-wear",
"labels": [
{
"type": "shirts",
"quantity": "20",
},
],
popular: true
},
{
"id": 2,
"group": "bottom-wear",
"lables": [
{
"type": "trousers",
"quantity": "31",
},
],
popular: true
},
];
const newDataToInsert = [
{
"type": 'blazers',
"quantity": 19
},
];
const updatedArray = data.map((d) => {
if (d.group && d.group === 'upper-wear') {
return { ...d, labels: d.labels.concat(newDataToInsert) }
} else {
return d;
}
});
console.log(updatedArray)
Explaination
Here while mapping the data, we check for the condition
IF
If it matches then we will first copy the whole object from the variable b return { ...b }
after that we take another variable with the same name lables return { ...d, labels: d.labels.concat(newDataToInsert) },As per the JSON default nature the new variable with the same name will hold the latest value
Here in labels we first take a copy of old data and then merge it with newDataToInsert array labels: d.labels.concat(newDataToInsert), It will merge 2 arrays and store them in JSON with the name labels
Else
In else we just return the current values else { return d; }
You don't actually need to iterate with map over the array. Just find an object in the array and change what you want.
const data=[{id:1,group:"upper-wear",labels:[{type:"shirts",quantity:"20"}],popular:true},{id:2,group:"bottom-wear",lables:[{type:"trousers",quantity:"31"}],popular:true}];
const newDataToInsert=[{type:"blazers",quantity:19}];
data.find(({ group }) => group === 'upper-wear')?.labels.push(...newDataToInsert);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're not returning all objects from your map. you're only returning a result when your criteria is met. This is resulting in your undefined objects...
const data = [
{ "id": 1, "group": "upper-wear", "labels": [ { "type": "shirts", "quantity": "20", }, ], popular: true },
{ "id": 2, "group": "bottom-wear", "lables": [ { "type": "trousers", "quantity": "31", }, ], popular: true },
]
const newDataToInsert = [ { "type": 'blazers',"quantity": 19 }, ]
const updatedArray = data.map(datum => {
if (datum.group === 'upper-wear') datum.labels = [...datum.labels, ...newDataToInsert]
return datum
});
console.log(updatedArray);
You can use Array#find to locate the desired group and then change labels for the group found. There are two options depending on how many items you would like to insert. Use Array#push to add the desired item; use forEach for more than one item:
const searchgroup = "upper-wear";
const target = data.find(({group}) => group === searchgroup);
target.labels.push(...newDataToInsert); //For one item to insert
//newDataToInsert.forEach(label => target.labels.push( label )); //For more than one item
const data = [{"id": 1, "group": "upper-wear", "labels": [{"type": "shirts", "quantity": "20"},],popular: true }, {"id": 2, "group": "bottom-wear", "lables": [{"type": "trousers", "quantity": "31", },],popular: true}];
const newDataToInsert = [{"type": 'blazers', "quantity": 19}];
//group to find
const searchgroup = "upper-wear";
//target element in data
const target = data.find(({group}) => group === searchgroup);
//check if group was found
if( target ) {
//if there's only one product in newDataToInsert us this:
//target.labels.push(...newDataToInsert);
//if you have more than one product to be inserted use this; also works for one
newDataToInsert.forEach(label => target.labels.push( label ));
} else {
console.log( `No such group found: ${searchgroup}!` );
}
console.log( data );
This is Browser localstorage Object referred as dataset
let dataset = localStorage.getItem('dataset') !== null ? leech : [];
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
This is the initial data object available I want to add more field to a particular id.
This is what I want :
[
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd",
"status":1
}
]
This my code to find the particular id
const user = dataset.find(user => user.id == 456);
Now how can I add status to user and update the user in the dataset?
You've already found the user by using Array.prototype.find() so all you need to do then is add the status property
// const dataset = JSON.parse(localStorage.getItem("dataset"))
const dataset = [{"id":123,"name":"abc"},{"id":456,"name":"bcd"}]
const user = dataset.find(({ id }) => id === 456)
if (user) {
user.status = 1
}
console.info(dataset)
.as-console-wrapper { max-height: 100% !important }
If you then want to store the modified data back into localStorage, use localStorage.setItem() and JSON.stringify()
localStorage.setItem("dataset", JSON.stringify(dataset))
If you want keep dataset initial value, and would like to get a new array, you can use Array.reduce() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
const output = dataset.reduce((acc, cur) => {
if (cur.id === 456) cur.status = 1;
acc.push(cur);
return acc;
}, []);
console.log(output);
If you want to update dataset, you can use Array.forEach() method.
const dataset = [
{
"id": 123,
"name": "abc"
},
{
"id": 456,
"name": "bcd"
}
]
dataset.forEach(user => {
if (user.id === 456) user.status = 1;
});
console.log(dataset);
You could do with Array#Findindex with callback return function. so could pass the originaldata,searchId and update object. In this method you could updated object easily
Why i suggest findIndex
Because findindex not running entire loop or iteration. If the match
detect on first iteration they will break the loop and returning the
result.For long iteration its more faster than other loop (reduce,forEach)
const data = [ { "id": 123, "name": "abc" }, { "id": 456, "name": "bcd" } ]
function update(dataset,searchId,addtionObject){
let ind = dataset.findIndex(({id}) => id == searchId);
dataset[ind] = {...dataset[ind],...addtionObject}; //join the new and old array
return dataset
}
console.log(update(data,456,{status:1}))
If you want to create new state objet, you can use immer for that.
Immer will produce the nextState based on the mutations to the draft state.
import produce from "immer";
const baseState = [
{
id: 123,
name: "abc",
},
{
id: 456,
name: "bcd",
},
];
const nextState = produce(baseState, (draftState) => {
draftState[1].status = 1;
});
I am using angular-highcharts for my project.I am used https://www.highcharts.com/demo/column-basic this chart for my data.I have below data format.
[
{
"project": "train project1",
"hours": {
"AD": 58265
}
},
{
"project": "butify",
"hours": {
"AD": 3940
}
},
{
"project": "skler",
"hours": {
"AD": 563250
}
},
{
"project": "Internal Application",
"hours": {
"AD": 33325,
"DAM": 328095
}
},
{
"project": "train2project",
"hours": {
"AD": 137215
}
},
{
"project": "CELLProje1",
"hours": {
"DAM": 488470
}
},
{
"project": "rangeselector",
"hours": {
"AD": 3015,
"DAM": 71175
}
},
{
"project": "Android dev",
"hours": {
"AD": 99160
}
},
{
"project": "Web Application",
"hours": {
"AD": 72720
}
}
];
The values inside "hours" will be one or more.I have added my fiddle tried so far.I struggling to form json for series data.Also I need form X -axis for the graph that should be in an array.
Ex:
categories: [
'train project1',
'beautify',
'skler',
'Internal Application',
'train project2',
'rangeselector',
'Android',
'Web Application'
],
X-axis formation will be right?
http://jsfiddle.net/harifrais/uxpvs8fw/34/
You're trying to get data into this format
[
{
name:"series-name",
data:[ ... ]
}
]
But to use categories, there must be the same number of elements in each series as there are categories. And as every hours element in your input data does not contain all the same you need to do a little more work.
Get a distinct list of all the keys from hours
Loop over every element and use project as a category
Fill in zeros where any element does not occur in hours
So you can do this in a fairly simple 2-step process using reduce and map.
var data = [{"project":"train project1","hours":{"AD":58265}},{"project":"butify","hours":{"AD":3940}},{"project":"skler","hours":{"AD":563250}},{"project":"Internal Application","hours":{"AD":33325,"DAM":328095}},{"project":"train2project","hours":{"AD":137215}},{"project":"CELLProje1","hours":{"DAM":488470}},{"project":"rangeselector","hours":{"AD":3015,"DAM":71175}},{"project":"Android dev","hours":{"AD":99160}},{"project":"Web Application","hours":{"AD":72720}}];
// get a distinct list of hour keys
var seriesData = data.reduce( (acc, {hours}) => {
Object.keys(hours).forEach(key => {
if(!acc[key]) acc[key] = [];
})
return acc;
},{});
// reduce the original data to get categories and series values
// filling in zeros where necessary
var result = data.reduce( (acc, {project,hours}) => {
acc.categories.push(project);
Object.keys(acc.seriesData).forEach(s => {
acc.seriesData[s].push(hours[s] || 0);
});
return acc;
},{categories:[],seriesData:seriesData});
// shape the data to how highcharts wants it
var categories = result.categories;
var series = Object.entries(result.seriesData).map( e => ({
name: e[0],
data:e[1]
}));
console.log(categories);
console.log(series);
Here's an updated fiddle to show highcharts/your data: https://jsfiddle.net/u7opL2dw/2/
Here is my idea how to parse your data to using in the Highcharts library, no matter how many properties will be in the data.hours object.
Demo: http://jsfiddle.net/BlackLabel/31tp0mkw/
const categories = sampleJson.map(data => data.project);
const getSeriesNames = sampleJson.map(data => {
for (let i in data.hours) {
return i
}
}).filter((item, i, ar) => ar.indexOf(item) === i);
const series = getSeriesNames.map(name => {
let output = {
name: name,
data: []
};
sampleJson.forEach(data => {
if (data.hours[name]) {
output.data.push(data.hours[name])
} else {
output.data.push(null)
}
});
return output
})
I have a set of checkboxes - which the user ticks on. The checkboxes pass some data an id and a name that i need later on for sorting. Because two objects are not equal even though they contain the same values I cant use Array.includes.
Here is an example of the data
[
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "earnings_group_ids"
},
{
"id": 3,
"name": "earnings_group_ids"
},
]
This is the current function (which would work if the items were not objects
const submitFilterDetails = (value) => {
return async (dispatch,getState) => {
const currentArray = (getState().filter.filtersArray);
if(!currentArray.includes(value)) {
dispatch(addToFiltersArray(value))
} else {
dispatch(removeFromFiltersArray(value));
}
}
}
How can you sort this so I only have unique values
You can use find :
YourArray.find(obj => obj.id == value.id && obj.name == value.name);
const src = [
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 1,
"name": "earnings_group_ids"
},
]
const out = src.reduce((acc, curr) => acc.some(i => i.id === curr.id) ? acc : acc.concat([curr]) , [])
// the `out` variable has 2 unique items
So, I have data. It is array of objects.
data = [
{
"id": "200",
"price": "5000"
},
{
"id": "137",
"price": "8000"
},
{
"id": "230",
"price": "9000"
},
{
"id": "241",
"price": "9000"
},
{
"id": "78",
"price": "10000"
}
]
json=JSON.parse(data);
I make something like pager.
My code should return nearby (previous and next) elements of original element.
It is not allowed to change order of objects.
I'm trying to do something like
json.indexOf(JSON.parse('{"id":"200","price":"5000"}'))
but it returns -1.
Also json[0]==JSON.parse('{"id":"200","price":"5000"}') return false, but I think that this elements are similar.
What way do you see?
json=JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(json.indexOf(JSON.parse('{"id":"200","price":"5000"}')));
console.log(json[0]==JSON.parse('{"id":"200","price":"5000"}'));
console.log(json[0]);
console.log(JSON.parse('{"id":"200","price":"5000"}'));
You could take a function which finds the index of the wanted id and returns items before that index, the index and one after the index with adjustment at the beginning of the array.
function getParts(id) {
var index = array.findIndex(o => o.id === id),
min = Math.max(index - 1, 0);
if (index !== -1) {
return array.slice(min, min + (index ? 3 : 2));
}
}
var array = JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(getParts('200'));
console.log(getParts('137'));
console.log(getParts('230'));
console.log(getParts('78'));
Try this, i think it would work as the 'id' property is unique
var words = [{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}];
let k;
let sayYourKeyId = "137";
const result = words.find((word, index) => {
if(word.id == sayYourKeyId){
k = index;
}
});
console.log(words[k-1]);
console.log(words[k]);
console.log(words[k+1]);