First off, apologies if this is normally a simple thing, but I'm not particularly experienced in JS. I'm trying to make some graphs in Plotly.js for a work site that currently holds raw JSON. We have a JSON in the format:
stuff = [{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
And I need the result to look like:
computed = [{"name":"shark", "location":"somewhere", "number":35},
{"name":"shark", "location":"somewhereelse", "number":50},
{"name":"turtle", "location":"anotherplace", "number":1},
{"name":"elephant", "location":"greatplace", "number":125}
Where all names are grouped by location and all numbers in that group are summed. It is then this computed JSON that I'll be using to graph with Plotly.js with some functions I have already built.
I think I can simplify the problem as:
forEach((item) => {
x.push(item['location']
y.push(y += stuff.number where stuff.location === x[-1])
}
But this also means I'll get the same number of rows as in stuff, just computed and graphed. I'm afraid I can't figure it out any further.
Any help would be muchly appreciated.
Simply looping out the original array, and adding the elements to a new array unless they are added already, or just adding the number will be the trick here. Here's the defined one:
var computed: any = [];
for(var element of stuff){
let computedElement = computed.find((ele: { location: string; }) => ele.location == element.location);
if (computedElement){
computedElement.number += element.number;
}
else{
computed.push(element);
}
}
First of all, json starts with {} and not []. Your object is a javascript object. I did a very long function below:
const stuffList = [
{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
]
//extract all available location
const locations = stuffList.map( stuffItem => {
return stuffItem.location
})
const filteredStuff = locations.map( location => {
const number= stuffList.map( stuffItem => {
if(stuffItem.location === location) {
return stuffItem.number
}
return 0
}).reduce( (a, b) => a + b)// total all the numbers of mathcing
location
//get the first newStuffItem value equals to location
const [filteredStuffItem] = stuffList.map( stuffItem => {
if(stuffItem.location === location) {
return {
name: stuffItem.name,
location,
number
}
}
}).filter( stuffItem => {
return stuffItem?.location === location
})
return filteredStuffItem
})
const newStuffList = filteredStuff.filter((thing, index) => {
const _thing = JSON.stringify(thing);
return index === filteredStuff.findIndex(obj => {
return JSON.stringify(obj) === _thing;
})
});
console.log(newStuffList)
OR the magic by Deepak in javascript:
const stuff = [
{"name": "shark", "location": "somewhere", "number":10},
{"name": "shark", "location": "somewhereelse", "number":50},
{"name": "shark", "location": "somewhere", "number":25},
{"name": "turtle", "location": "anotherplace", "number":1},
{"name": "elephant", "location": "greatplace", "number":50},
{"name": "elephant", "location": "greatplace", "number":75}
]
var computed = [];
for(var element of stuff){
let computedElement = computed.find((ele) => ele.location == element.location);
if (computedElement){
computedElement.number += element.number;
}
else{
computed.push(element);
}
}
console.log(computed)
Sorry for not replying to this sooner, and thanks to those who commented. For whatever reason I couldn't get the other suggested solutions to work but I seeing another perspective on the logic needed helped me figure it out.
if (!label.includes(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])) {
label.push(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])
x.push(item['date'])
y.push(item['sum'])
} else {
var indx = label.indexOf(item['specimen'] + ':' + item['well_label'] + ':' + item['run'] + ':' + item['group'])
let summed = y[indx] + item['sum']
y.splice(indx, 1, summed)
So essentially this created something akin to a compound key, and pushes the initial data to add it to the label list and then the data to the relevant lists. If that compound key appears again then the value is just updated with the splice method.
Only issue is that because these lists are not linked in anyway than the data being input to them, there is a rare chance of the right label and data not matching up but after a lot of testing I have sorted that out and it does work.
Again thanks to the previous commenters that helped.
Related
This question already has answers here:
Javascript equivalent of Python's zip function
(24 answers)
Is there a ways to combine objects in Javascript
(1 answer)
Closed 3 years ago.
I am trying to combine two object arrays using either Javascript or Jquery but it is not resulting the way I am expecting it to be. These are my array objects results:
Arry1 Results: [{"name": "2412"}, {"name": "3324"}, {"name": "8875"}]
Arry2 Results: [{"zip": "12051"}, {"zip": "54021"}, {"zip": "24521"}]
This is what I have done to push one into the other:
Array.prototype.push.apply(Arry1,Arry2);
The issue is the above code stacks them together. The object structure I am trying to get is as follows:
[
{
"name": "2412",
"zip": "12051"
},
{
"name": "3324",
"zip": "54021"
},
{
"name": "8875",
"zip": "24521"
}
]
Map the arrays into each other by cloning and combining with Object.assign
let a1 = [{"name": "2412"}, {"name": "3324"}, {"name": "8875"}];
let a2 = [{"zip": "12051"}, {"zip": "54021"}, {"zip": "24521"}];
let result = a1.map((props, index) => Object.assign(props, a2[index]));
console.log(result);
Edit Based on Comment:
If this is a utility you're going to be using often with a variable number of arrays, you may consider creating a function that handles it.
let a1 = [{"name": "2412"}, {"name": "3324"}, {"name": "8875"}],
a2 = [{"zip": "12051"}, {"zip": "54021"}, {"zip": "24521"}],
a3 = [{"phone": "1234"},{"phone": "3121"},{"phone": "2136"}];
function combine(first, ...arrs) {
let result = first.map((props, index) => {
let combined = [props];
arrs.forEach(arr => combined.push(arr[index]));
return Object.assign(...combined);
})
return result;
};
let result = combine(a1, a2, a3);
console.log(result);
You can use map:
const arr1 = [{"name": "2412"}, {"name": "3324"}, {"name": "8875"}];
const arr2 = [{"zip": "12051"}, {"zip": "54021"}, {"zip": "24521"}];
let result = arr1.map((obj, idx) => {
obj.zip = arr2[idx].zip;
return obj
});
console.log(result)
There are multiple ways to do this. The below is one of,
let array1 = [{"name": "2412"}, {"name": "3324"}, {"name": "8875"}];
let array2 = [{"zip": "12051"}, {"zip": "54021"}, {"zip": "24521"}];
let resultArray = [];
for(let i=0; i< array1.length; i++) { // we can consider any of array1 or array 2 length
resultArray.push({...array1[i], ...array2[i]});
}
console.log(resultArray);
OR
With Jquery, we can go like below,
let array1 = [{ name: "2412" }, { name: "3324" }, { name: "8875" }];
let array2 = [{ zip: "12051" }, { zip: "54021" }, { zip: "24521" }];
let resultArray = [];
$.each(array1, function(index, value) {
resultArray.push($.extend(value, array2[index]));
});
console.log(resultArray);
I have an array of objects and want to filter it based on values of another string array and remove the objects that doesn't contain any of the strings.
I tried using split for the string array and search for each term in a forEach but it didn't work then tried the following which works as a filter but it filters for exact match not partial.
var employees = [
{"name": "zxc asd", "age":"30"},
{"name": "asd", "age":"24"},
{"name": "qwe", "age":"44"},
{"name": "zxc", "age":"28"},
];
var keepNames = ["asd", "qwe"];
keepNames = keepNames.map(name => {
return name.toLowerCase();
});
var filteredEmployees = employees.filter(emp => {
return keepNames.indexOf(emp.name.toLowerCase()) !== -1;
});
console.log( filteredEmployees );
Expected Output[
{"name": "zxc asd", "age":"30"},
{"name": "asd", "age":"24"},
{"name": "qwe", "age":"44"}];
Actual Output [
{"name": "asd", "age":"24"},
{"name": "qwe", "age":"44"}]
I'd really appreciate any help.
Thanks in advance
You need to iterate the array with names keep as well and check the value.
var employees = [{ name: "zxc asd", age: "30" }, { name: "asd", age: "24" }, { name: "qwe", age: "44" }, { name: "zxc", age: "28" }],
keep = ["asd", "qwe"],
filtered = employees.filter(({ name }) =>
keep.some(n => name.toLowerCase().includes(n))
);
console.log(filtered);
.as-console-wrapper { max-height: 100% !important; top: 0; }
indexOf uses strict equality so it won't match partially.
You can use some and includes
var employees = [ {"name": "zxc asd", "age":"30"},{"name": "asd", "age":"24"},{"name": "qwe", "age":"44"},{"name": "zxc", "age":"28"},];
var filterBy = ["asd", "qwe"];
var filteredEmployees = employees.filter(emp => {
return filterBy.some(v => emp.name.toLowerCase().includes(v.toLowerCase()))
});
console.log(filteredEmployees);
I will only get an object in comparison the id that from is decided from the user with objects of the arrays.
var laptops = [{
"name": "Firefox",
"age": 30,
"id": "ab"
},
{
"name": "Google",
"age": 35,
"id": "cd",
"date": "00.02.1990"
},
{
"name": "Microsoft",
"id": "ef",
"age": 40
}
];
getLaptopByAsin(id: string) {
var laptop = this.laptops.find(
(laptopObject) => {
return laptopObject.name === id;
}
);
return laptop;
}
var enter = "cd";
name = this.getLaptopByAsin(enter).name;
age = this.getLaptopByAsin(enter).age;
date = this.getLaptopByAsin(enter).date;
console.log(name)
console.log(age)
console.log(date)
Your problem is that you filter on name:
this.laptops.find(
(laptopObject) => {
return laptopObject.name === id;
}
);
After fixing your issue and do some refactoring, the code becomes this:
getLaptopByAsin(id: string) {
return this.laptops.find(
laptopObject => laptopObject.id === id
);
}
Some other comments:
Try to use const instead of var more often where possible.
Saving date the way you do, might give you some headache in the future. use some standard instead, like https://en.wikipedia.org/wiki/Epoch
Avoid multiple function calls when they are not needed, save the result from getLaptopByAsin to a variable (const foundLaptop) so you don't need to iterate over the array multiple times. eg:
const foundLaptop = this.getLaptopByAsin('cd');
console.log(foundLaptop.name);
console.log(foundLaptop.age, foundLaptop.date);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have the following code. I'm trying to output each key value ("company" and "address") the different "city1, 2 ,3" object (list goes on and on in the real example). in to a <p> using javascript. I am feeling a bit lost since I've tried a lot of different ways but I can't get it to work. I believe it might be due to the structure. If it would only be one city there would be no problem.
var data = {
"city1":
[
{
"company": "Ica kvantum",
"address": "Orrgatan 3-5"
},
{
"company": "Hemköp",
"address": "Allegatan 26"
}
],
"city2":
[
{
"company": "Ica Nära",
"address": "Centrumvägen 7"
}
],
"city3":
[
{
"company": "Hora brothers kiosk",
"address": "Rövsgatan 43"
},
{
"company": "Microsoft",
"address": "Husvägen 38"
}
]
};
You can iterate the data object using for...in and then iterate the array inside with forEach.
var body = '';
for(var city in data) {
data[city].forEach(function(entry) {
body += '<p>' + entry.company + ', ' + entry.address + '</p>';
});
}
console.log(body);
If it's reasonable within your product requirements, you might consider using list elements rather than a simple <p>. Try to use the appropriate document.createElement methods rather than building a string. Something like:
var data = {
"city1": [{
"company": "Ica kvantum",
"address": "Orrgatan 3-5"
}, {
"company": "Hemköp",
"address": "Allegatan 26"
}],
"city2": [{
"company": "Ica Nära",
"address": "Centrumvägen 7"
}],
"city3": [{
"company": "Hora brothers kiosk",
"address": "Rövsgatan 43"
}, {
"company": "Microsoft",
"address": "Husvägen 38"
}]
};
var cityList = document.getElementById("city-list");
for (var cityName in data) {
if (data.hasOwnProperty(cityName)) {
var city = document.createElement("li");
var cityLabel = document.createElement("p");
cityLabel.textContent = cityName;
city.appendChild(cityLabel);
var companyList = document.createElement("ul");
city.appendChild(companyList);
var companies = data[cityName];
for (var i = 0; i < companies.length; ++i) {
var company = document.createElement("li");
company.textContent = companies[i].company + ": " + companies[i].address;
companyList.appendChild(company);
}
cityList.appendChild(city);
}
}
<ol id="city-list"></ol>
Similar to Ben's answer. I personally like plain for..in loops over foreaches in javascript, but its a preference.
var data = {
"city1":
[
{
"company": "Ica kvantum",
"address": "Orrgatan 3-5"
},
{
"company": "Hemköp",
"address": "Allegatan 26"
}
],
...
};
var html = "";
for(var city in data)
{
//you can append the city to the html here if you want
// html += "<h2>" + city + "</h2>";
for(var company in data[city])
{
for(var field in data[city][company])
{
html += "<p>" + field + ": " + data[city][company][field] + "</p>";
}
}
}
The url has following json data:
[{ "topic": "cricket",
"value": "Player [ playerid=123, category=b, high=150, total=2300]",
"place": "xyz"},
{ "topic": "cricket",
"value": "Player [ playerid=456, category=c, high=60, total=300]",
"place": "abc"},
{ "topic": "cricket",
"value": "Player [ playerid=789, category=a, high=178, total=5300]",
"place": "bnm"}]
I tried online to check whether this is valid json or not through following link: http://jsonformatter.curiousconcept.com/ it says valid. if it is, how do I access each playerid ?
It is valid JSON, but the data about the player is embedded in a random string. You can do one of two things:
Update the service to send back a different, valid JS value, for example:
"value": {
"type": "Player",
"playerid": 123,
"category": "b",
"high": 150,
"total": 2300
}
Parse the data in the value key yourself:
// Simple regex, not really "parsing"
var playerIdRE = /playerid=(\d+)/i;
var result = playerIdRE.exec(yourData[0].value);
// result[0] is the full match, while result[1] is the ID.
// Or the more complicated version that does full parsing
var format = /\s*(.*?)\s*\[\s*([^\]]+)\s*\]\s*/gi,
keyValuePair = /(\w+)=([^,\]]*),?\s*/gi
function parseComplexDataType(input) {
var result = format.exec(input),
typeName = result[1],
keyValues = result[2],
returnValue = {};
if (!typeName) return returnValue;
returnValue.typeName = typeName;
input.replace(keyValuePair, function(_, key, value) {
returnValue[key] = value;
});
return returnValue;
}
// Usage:
> parseComplexDataType("Player [ playerid=123, category=b, high=150, total=2300]")
Object {typeName: "Player", playerid: "123", category: "b", high: "150", total: "2300"}
For your purposes, it is not valid. Once the JSON is corrected, you simply need to loop through the array and read each value.
var jArray = [{
"topic": "cricket",
"value": {
"type": "Player",
"playerid": 123,
"category": "b",
"high": 150,
"total": 2300
},
"place": "xyz"
}, {
...
}]
To access the JSON data ...
for (var i=0,len=jArray.length; i<len; i++) {
console.log(jArray[i].topic, jArray[i].value.type);
}
Yes, it is. I check it via: http://jsonlint.com/
Extracting "playerid":
Initialise the string to JSONArray.
Iterate over each element in the above array.
Now, from each element extract "value".
Finally, from this string you can get "playerid" by using string methods (see the code below).
Below is the code in Java:
ArrayList<String> player_ids = new ArrayList<String>();
String s = "YOUR STRING";
JSONArray ja = new JSONArray(s);
for(int i =0; i<ja.length(); i++)
{
String value = ja.getJSONObject(i).getString("value");
int start = value.indexOf("=");
int end = value.indexOf(",");
String player_id = value.substring(start+1, end);
player_ids.add(player_id);
}
Hope it helps!!