Related
I have a nested array that looks like this:
[["Organisation","ID","Name"],["ACME","123456","Bart Simpson"],["ACME","654321","Ned Flanders"],["ACME","1234","Edna Kabappel"],["Yahoogle","666666","Bon Scott"],["Yahoogle","99999","Neil Young"],["Yahoogle","111111","Shania Twain"]]
The first value in each array is the name of an organisation that an ID and name can belong to.
I am trying to find the simplest way to group all instances where an ID and name belong to the same company, under one 'key'.
So the above would result in something like this:
{
"ACME": [
{
"ID": 123456,
"Name": "Bart Simpson"
},
{
"ID": 654321,
"Name": "Ned Flanders"
},
{
"ID": 1234,
"Name": "Edna Kabappel"
}
],
"Yahoogle": [
{
"ID": 666666,
"Name": "Bon Scott"
},
{
"ID": 99999,
"Name": "Neil Young"
},
{
"ID": 111111,
"Name": "Shania Twain"
}
]
}
I have been playing around with for loops but I'm ending up with many many lines of code, trying to detect when the company name is different from the previous, and getting into a real mess with things.
I have searched a lot here trying to find something similar but have not had any luck.
I have only just started coding again for person interest after about 18 years and I'm very novice again.
Thank you in advance for any assistance.
lot of solutions to arrive at same result, one using lambda and reduce: this is a generic solution, just adapt the output push to build your final json.
const datas = [
["Organisation", "ID", "Name"],
["ACME", "123456", "Bart Simpson"],
["ACME", "654321", "Ned Flanders"],
["ACME", "1234", "Edna Kabappel"],
["Yahoogle", "666666", "Bon Scott"],
["Yahoogle", "99999", "Neil Young"],
["Yahoogle", "111111", "Shania Twain"]
];
const titles = datas.shift()
const groupBy = (x,f)=>x.reduce((a,b)=>((a[f(b)]||=[])
.push({[titles[1]]:b[1], [titles[2]]:b[2]}),a),{});
const result = groupBy(datas, v => v[0])
console.log(result)
Using Array.reduce. Please check if this works for you. In the below approach ID and Name is hard coded. You can try writing a generic dynamic approach which handle any number of params like ID, Name, Age etc.
const myArray = [
["Organisation", "ID", "Name"],
["ACME", "123456", "Bart Simpson"],
["ACME", "654321", "Ned Flanders"],
["ACME", "1234", "Edna Kabappel"],
["Yahoogle", "666666", "Bon Scott"],
["Yahoogle", "99999", "Neil Young"],
["Yahoogle", "111111", "Shania Twain"]
];
const obj = myArray.reduce((acc, value, index) => {
if (index === 0) return acc;
const key = value[0];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push({
ID: value[1],
Name: value[2]
});
return acc;
}, {});
console.log(obj);
In order to achieve what you want, you can follow below steps:
Create an object to store your result.
While you are running the loop you have to check whether name of the organization exists as a key in the object and add it if it does not, initializing it to an empty array. Then push the result you want to store into that array.
Below is a sample implementation, assuming your data is stored in data:
var result = {};
for(var i=1; i < data.length; i++){
if(!result.hasOwnProperty(data[i][0])){
result[data[i][0]] = [];
}
result[data[i][0]].push({ "ID": data[i][1], "Name": data[i][2]});
}
I am using ReactJS. I have an object which looks like this:
{
autumn=firstContactPersonName: "John",
autumn=firstContactPersonPhone: "46442644",
autumn=secondContactPersonName: "Jhonny",
autumn=secondContactPersonPhone: "46442644",
christmas=firstContactPersonName: "Tommy",
christmas=firstContactPersonPhone: "46442644",
christmas=secondContactPersonPhone: "Thomas",
winter=firstContactPersonPhone: "46442644",
winter=firstContactPersonName: "Peter",
winter=secondContactPersonName: "Tom",
winter=secondContactPersonPhone: "44664455"
}
How can I group them based on autumn, christmas, winter. So one object with autumn have the autumn fields, the second one christmas have the christmas field, and the third one winter have the winter fields?
And so on. All fields will have a segment name before =, so I can easily see what kind of segment they belong to.
This is achievable with pure JS, no need for lodash (which I'm not familiar with).
This function takes every property of your input object, splits the key around the equals sign for the season part (prefix) and rest (appendix). Afterwards it looks for an object in the output array with the same season and adds the properties to it. If there is no object with specified season, it creates a new one.
function processData(inputObj) {
var data = [];
for (var key in inputObj) {
var prefix = key.split("=")[0];
var appendix = key.split("=")[1];
var dataObject = data.find(o => o.season == prefix);
if (!dataObject) {
dataObject = {season: prefix};
data.push(dataObject);
}
dataObject[appendix] = inputObj[key];
}
return { data };
}
produces this output:
{
"data": [
{
"season": "autumn",
"firstContactPersonName": "John",
"firstContactPersonPhone": "46442644",
"secondContactPersonName": "Jhonny",
"secondContactPersonPhone": "46442644"
},
{
"season": "christmas",
"firstContactPersonName": "Tommy",
"firstContactPersonPhone": "46442644",
"secondContactPersonPhone": "Thomas"
},
{
"season": "winter",
"firstContactPersonPhone": "46442644",
"firstContactPersonName": "Peter",
"secondContactPersonName": "Tom",
"secondContactPersonPhone": "44664455"
}
]
}
You can produce your groups by looping over the keys in the object. Split the key on = and capture the results. The first element should be the group, the second the property to access within this group.
Create a new object if a group doesn't yet exist. Then set the property within the group equal to the value of the original object.
const input = {
"autumn=firstContactPersonName": "John",
"autumn=firstContactPersonPhone": "46442644",
"autumn=secondContactPersonName": "Jhonny",
"autumn=secondContactPersonPhone": "46442644",
"christmas=firstContactPersonName": "Tommy",
"christmas=firstContactPersonPhone": "46442644",
"christmas=secondContactPersonPhone": "Thomas",
"winter=firstContactPersonPhone": "46442644",
"winter=firstContactPersonName": "Peter",
"winter=secondContactPersonName": "Tom",
"winter=secondContactPersonPhone": "44664455"
};
const output = {};
for (const key in input) {
const [season, property] = key.split("=", 2);
if (!output[season]) output[season] = {};
output[season][property] = input[key];
}
console.log(output);
I find my explanation a bit confusion, but I hope that combined with the code snippet you understand what I'm saying.
Use Object.entries() to generate an array of [key, value] pairs, and iterate with Array.reduce(). For each pair, split the key by = to get the group key, and the value key, create the group's object if none exists, and assign the value to the object.
const data = {"autumn=firstContactPersonName":"John","autumn=firstContactPersonPhone":"46442644","autumn=secondContactPersonName":"Jhonny","autumn=secondContactPersonPhone":"46442644","christmas=firstContactPersonName":"Tommy","christmas=firstContactPersonPhone":"46442644","christmas=secondContactPersonPhone":"Thomas","winter=firstContactPersonPhone":"46442644","winter=firstContactPersonName":"Peter","winter=secondContactPersonName":"Tom","winter=secondContactPersonPhone":"44664455"}
const result = Object.entries(data)
.reduce((r, [k, v]) => {
const [gKey, key] = k.split('=') // get the key
r[gKey] = r[gKey] || {} // generate the object if it doesn't exist
r[gKey][key] = v // assign the value to the object
return r
}, {})
console.log(result);
I have 3 different jsons, I need to extrapolate some data from each and create a new json with it. The three jsons have an id identifier in common, a unique identifier, so We could use that as a match since they are actually three different big jsons.
On json one we have "id":"265", on two and three "article_id":"265", so these can be the reference point when we loop.
I never worked with json this way so I wouldn't know how to approach it. I have put jQuery and JS as tags as they're what I know best.
1
{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
}
2
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
}
3
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}
So the end result I am looking for is a single json exactly like this, we take id and title as objects from json 1, then we grab original_name from json two and year object from json three and we'll have:
{
"id":"265",
"title":"Battle of Gettysburg",
"original_name":"United States",
"year":"1863"
}
NOTE
The json above are just examples, in reality they are three huge lists, what I could do (manually), is to join them in order to have a single json.
There is some terminology confusion here; based on your comments you could be asking one of two very different questions. Fortunately one of them is very simple to answer so let's do both.
(I am handwaving past the details of loading json strings into the browser and converting them into javascript objects.)
If you have three objects
...then this is just a matter of plucking out the fields you need individually when constructing an output object:
var in1 = {
"id": "265",
"title": "Battle of Gettysburg",
"page_id": "4849",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
};
var in2 = {
"id": "185",
"original_name": "United States",
"country_id": "24",
"article_id": "265"
}
var in3 = {
"id": "73",
"month": "July",
"year": "1863",
"suffix": "",
"article_id": "265"
}
// construct a new object using the selected fields
// from each object in1, in2, or in3:
var out = {
id: in1.id,
title: in1.title,
original_name: in2.original_name,
year: in3.year
}
console.log(out);
If you have three lists of objects:
...in this case it's a lot more complicated (and a lot more interesting). In this case you would need to match fields from the objects in each list which share the same IDs.
The following is definitely not the most efficient or memory-conserving way to do this; I've spread things out to (hopefully) make it easier to follow what it's doing.
I'm making two assumptions:
within each list, all IDs are unique (meaning you won't have two objects with the same ID in one JSON file)
Every ID will appear in all three lists (meaning you don't need to handle missing fields in output)
/* Again handwaving past loading JSON strings and parsing
them into javascript objects, we'll just start with
three arrays: */
var input1 = [{
"id": "265",
"title": "Battle of Gettysburg",
"page_id": "4849",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
},
{
"id": "1",
"title": "Foo",
"page_id": "123",
"language_id": "en",
"original_time": "July 1\u20133, 1863"
}
];
var input2 = [{
"id": "1",
"original_name": "Bar",
"country_id": "24",
"article_id": "265"
},
{
"id": "265",
"original_name": "United States",
"country_id": "24",
"article_id": "265"
}
]
var input3 = [{
"id": "1",
"month": "July",
"year": "Baz",
"suffix": "",
"article_id": "265"
},
{
"id": "265",
"month": "July",
"year": "1863",
"suffix": "",
"article_id": "265"
}
]
/* It would be much easier to find corresponding IDs
across these arrays if they weren't arrays. We'll
start by converting them into objects keyed by the
item ids: */
var convertArray = function(arr) {
var output = {};
arr.forEach(function(o) {
output[o.id] = o;
});
return output;
}
var obj1 = convertArray(input1);
var obj2 = convertArray(input2);
var obj3 = convertArray(input3);
/* Now if we need to find (say) the object with id "foo", we don't
need to search the whole array, but can just use `obj1["foo"]` or
`obj1.foo`.
The last step is to iterate over the list of IDs and repeatedly
do basically the same thing as in the "if you have three objects"
part above. The only difference is that we need to access the
object with the same ID in each of the input lists: */
var constructOutput = function(in1, in2, in3) {
var output = []; // we'll be outputting a list of objects again.
// step through every ID (assuming in1 contains all of them):
Object.keys(in1).forEach(function(id) {
var obj = {
id: id,
title: in1[id].title,
original_name: in2[id].original_name,
year: in3[id].year
}
output.push(obj);
});
return output;
}
var final = constructOutput(obj1, obj2, obj3)
console.log(final)
Essentially what you have to do is mimic a SQL JOIN using JavaScript objects:
Use JSON.parse() on all three JSON collections to turn them into arrays of objects.
Iterate through JSON 1 objects; for each object...
Iterate through JSON 2 objects, testing if article ID matches the ID from JSON 1 that we are iterating over. Save this object.
Iterate through JSON 3 objects, testing if ID matches the ID of the object we found from JSON 2. Save this object.
After you have all three objects, make a new object literal that contains only the fields you want:
{
Id: obj1.id,
Title: obj1.title,
Original_name: obj2.original_name,
Year: obj3.year
}
Should you want to combine n number of JSON objects, e.g. a list of objects you can take a functional approach and utilise reduce + filter.
const data = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
},
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}];
const final = data.reduce((accu, { id, title }, index, array) => {
// Find any related objects
const matches = array.filter(data => data.article_id === id);
if (matches.length) {
// Flatten them for ease of access. Duplicate keys will override.
const flat = matches.reduce((arr, item) => ({ ...arr, ...item }), [])
// Return new object
return accu.concat({
...flat,
id,
title,
});
}
return accu;
}, []);
console.log(final, '<<')
// Witness
document.getElementById('results').innerHTML = JSON.stringify(final);
<div id="results" style="font-family: Courier; font-size 14px; color: #fff; background: #000; padding: 20px; max-width: 80vw;"></div>
Edited*
Maybe this is what you need?
let arrPages = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
}];
let arrArticles = [{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}];
let getResult = (arrInput, arrCompare) => {
let joinedItems = [];
arrInput.forEach(item => {
let newItem = { id: item.id, title: item.title };
arrCompare.forEach(subItem => {
if(subItem.article_id !== undefined && subItem.article_id === item.id){
if(subItem.original_name !== undefined)
newItem.original_name = subItem.original_name;
if(subItem.year !== undefined)
newItem.year = subItem.year;
}
});
joinedItems.push(newItem);
});
return joinedItems;
};
let result = getResult(arrPages, arrArticles);
console.log(result);
In the first part of the code i create a var that has the json data.
To solve the problema i create 2 functions, the order of the creation dosen't metter, the first function getJSONData() take the json data as parameter and return a object filtered by the keys defined in the array keys. The secound function just check if the current key is present in the array of keys, this function could be replaced by the jQuery.inArray() method.
// JSON data
var json = [{
"id":"265",
"title":"Battle of Gettysburg",
"page_id":"4849",
"language_id":"en",
"original_time":"July 1\u20133, 1863"
},
{
"id":"185",
"original_name":"United States",
"country_id":"24",
"article_id":"265"
},
{
"id":"73",
"month":"July",
"year":"1863",
"suffix":"",
"article_id":"265"
}]
// keys that i want
var keys = ["title", "original_name", "year"];
// var that will have the filtered data
var newJSON = getJSONData(json);
console.log(JSON.stringify(newJSON))
// this is the main function of the code
// here we iterate in the json creating a new object that has all the tags definid in the keys array
function getJSONData(arrayJSON){
var JSONFiltered = {};
for(var i in arrayJSON){
for(var key in arrayJSON[i]){
if(hasElement(key)){
JSONFiltered[key] = arrayJSON[i][key];
}
}
}
return JSONFiltered;
}
// this function is used to check a key is present in the array of keys
function hasElement(key){
for(var elem in keys){
if(keys[elem] == key) return true;
}
return false;
}
I got stuck trying to retrive array items. So here is the deal. I have a two dimentional array which has value and key so example of my data is:
[
Object { css="SS", title="Apple"},
Object { css="SS", title="Orange"},
Object { css="SS", title="Banana"}
]
I want to see if an object exists in the array above. And I have no idea why its not working, here is my code to find the object:
jQuery.inArray("Apple", fruits["title"]); //this returns -1 why?
Any ideas how to search two dimensional array?
This is not a 2D array, this is an array of objects, so this should work:
for (var i = 0; i < array.length; i++) {
console.log(array[i].title); //Log the title of each object.
if (array[i].title == "Apple") {
console.log("Found apple!");
}
}
Also, objects are key/val pairs, denoted by key : val, not key = val. Your array has syntax errors and shouldn't run.
To be pedantic, you have an array of objects, not a 2d array. Also your syntax for the object parameters is incorrect.
You can use filter() on the array to find the values:
var array = [
{ css: "SS", title: "Apple"},
{ css: "SS", title: "Orange"},
{ css: "SS", title: "Banana"}
];
var matches = array.filter(function (obj) { return obj.title == "Apple" });
if (matches.length) {
// Apple was in the array...
}
If you have an object like this
var peoples = [
{ "name": "bob", "dinner": "pizza" },
{ "name": "john", "dinner": "sushi" },
{ "name": "larry", "dinner": "hummus" }
];
Ignore what's below. Use the filter method!
peoples.filter(function (person) { return person.dinner == "sushi" });
// => [{ "name": "john", "dinner": "sushi" }]
You can search for people who have "dinner": "sushi" using a map
peoples.map(function (person) {
if (person.dinner == "sushi") {
return person
} else {
return null
}
}); // => [null, { "name": "john", "dinner": "sushi" }, null]
or a reduce
peoples.reduce(function (sushiPeople, person) {
if (person.dinner == "sushi") {
return sushiPeople.concat(person);
} else {
return sushiPeople
}
}, []); // => [{ "name": "john", "dinner": "sushi" }]
I'm sure you are able to generalize this to arbitrary keys and values!
fruits probably is a array, fruits["title"] therefor doesn't exist.
You might want to transform your data:
var fruitTitles = fruits.map(function(f) { return f.title; });
jQuery.inArray("Apple", fruitTitles);
From the jQuery docs:
jQuery.inArray( value, array [, fromIndex ] )
I've never used this method, but a quick guess:
var hasIt = jQuery.inArray({css:"SS",title:"Apple"}, myArray);
As the $.inArray() documentation explains, the first argument to the function is the value to search for. Your array does not have any elements that are equal to the string "Apple" that you have supplied in the first argument because none of your array elements are strings (they're all objects).
The second argument to $.inArray() is supposed to be the array itself, but (assuming fruits is the array you show) fruits["title"] is undefined because your array has no property called "title", only the objects in the array have that property.
Try this instead:
var index = $.inArray("Apple", $.map(fruits, function(el) { return el.title; }));
try this code
var fruits = [
{ css:"SS", title:"Apple"},
{ css:"SS", title:"Orange"},
{ css:"SS", title:"Banana"}
];
jQuery.grep(fruits,function(fruit){return fruit.title == 'Apple'});
I'm positive this question must have been covered before, but I can quite find it. So....
I have an object like so
Object
name: Fred
lastname: Jones
city: Los Angeles
I'd like to use Javascript to convert it to a string that looks like this:
//Do want this
[
{"name": "name", "value": "Fred"},
{"name": "lastname", "value": "Jones"},
{"name": "city", "value": "Los Angeles"}
]
All of the examples I've found use JSON.parse() to get a result that looks like this (which I don't want):
//Don't want this
[
{"name": "Fred", "lastname": "Jones", "city": "Los Angeles"}
]
I'm working with another developer who says this is how Jquery parses objects (EDIT- he's using $serializeArray(), so perhaps JQuery has a method to help me with this.
Any ideas would be most welcome.
Thanks!
This conversion calls for iterating through the properties of the source object and accumulating entries in a result array.
function toList( obj ) {
var rv = [], k;
for (k in obj) {
if (obj.hasOwnProperty(k))
rv.push({ name: k, value: obj[k] });
}
return rv;
}
var list = toList( myObject );
var arr = []
for (var key in object_name) {
arr.push({'name': key, 'value': object_name[key]})
}
Loop through the keys and add it to the array.
You can loop through the object properties and create the array
var a = array();
for (p in obj) {
a.push({'name': p, 'value': obj[p]});
}
This should get the structure that you want.
You should be able to do it in a simple for..in loop.
var yourObject = { name: "Fred", lastname: "Jones", city: "Los Angeles" },
parsed = [];
for(var i in yourObject){
parsed.push({ name: i, value: yourObject[i]})
}