Iterate through JavaScript objects to produce an array of objects - javascript

I have an array of objects. One of the objects looks like this:
obj1 = {
name: 'rich',
email: 'rich#test.com',
date: {
greg : {
name: 'greg',
id: 1234}
}
}
How can I iterate through this array of objects (called usersArray) and add it to another array of objects (called usersArrayObj) with each object containing the name of the user (e.g. rich) and the name of the other (e.g. greg)
so that my end result would look like the below:
obj1 = {
name: 'rich',
pairName: 'greg',
}
I have tried to use hasOwnProperty and so forth but they behaving a little bit funky...

You can map the array like this:
var myArray = [
{ name: 'rich', email: 'rich#test.com', date: { greg: { name: 'greg', id: 1234 } } },
{ name: 'foo', email: 'foo#test.com', date: { bar: { name: 'bar', id: 5678 } } }
];
var results = myArray.map(function(item) { // For each item in the array
return { // Return an object,
name: item.name, // Using the current item's name
pairName: Object.keys(item.date)[0] // And the first key found on `item.date`
};
});
console.log(results);

This solution uses ES6. Use Array.prototype.map() and extract the object (inside greg:) using Object.values() (the the browser's support in the link):
const arr = [{
name: 'rich',
email: 'rich#test.com',
date: {
greg: {
name: 'greg',
id: 1234
}
}
}];
const result = arr.map(({ name, date }) => ({
name,
pairName: Object.values(date)[0].name
}));
console.log(result);

You can use Array.prototype.map() to crate the new array
To select the first key inside the object data you can use Object.keys() that will return you an array of a given object's own enumerable properties. You can then select the first element [0]
var usersArray = [{
"name": 'rich',
"email": 'rich#test.com',
"date": {
"greg": {
"name": 'greg',
"id": 1234
}
}
}, {
"name": 'jason',
"email": 'jason#test.com',
"date": {
"mickael": {
"name": 'mickael',
"id": 5678
}
}
}];
var usersArrayObj = usersArray.map(function(user) {
return {
"name": user.name,
"pairName": Object.keys(user.date)[0]
}
});
console.log(usersArrayObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }

for this case what you can use is Object.keys() JS function.
obj2= {
name:obj1.name,
pairName: Object.keys(obj1.date)[0]
}

var arr = [{
name: 'rich',
email: 'rich#test.com',
date: {
greg : {
name: 'greg',
id: 1234}
}
}]
var newArr = [];
for (var i = 0; i < arr.length; i++) newArr[i] = {
name: arr[i].name,
pairName: Object.keys(arr[i].date)[0]
};
JSON.stringify(newArr); // "[{"name":"rich","pairName":"greg"}]"

Related

How to merge object with jquery by id

I need to be able to concatenate two JavaScript objects like the following:
let arr1 = [
{"0": { id: "abdc4051", date: "2017-01-24" }},
{"1": { id: "abdc4052", date: "2017-01-22" }}
];
let arr2 = [
{"0": { category: "Sport", data: {code: "abdc4051", name: "ab"} } },
{"1": { category: "Others", data: {code: "abdc4052", name: "abc"} } }
];
Does anyone have a script for this or know of a built in way to do this?
I want the date to be added in the data on arr2 with the condition code equal to id
Your object shape makes this harder than it should be. Are you certain you want the sequential properties in each object, or is that an artifact of logging/poor parsing?
You'll need to work around them if you actually need them, in the snippet below using Object.values() in creating a Map from arr1, and using Object.entries() in the final map() call on arr2 to store the sequential key and then reintroduce it in the return after the merge logic.
const
arr1 = [{ "0": { id: "abdc4051", date: "2017-01-24" } }, { "1": { id: "abdc4052", date: "2017-01-22" } }],
arr2 = [{ "0": { category: "Sport", data: { code: "abdc4051", name: "ab" } } }, { "1": { category: "Others", data: { code: "abdc4052", name: "abc" } } }],
// create map of dates: Map(2) { 'abdc4051' => '2017-01-24', 'abdc4052' => '2017-01-22' }
dateMap = new Map(arr1.map(o => {
const [{ id, date }] = Object.values(o);
return [id, date];
})),
// map over arr2, get date from Map and add it to 'data' if it exists
result = arr2.map(o => {
const [[k, _o]] = Object.entries(o);
const date = dateMap.get(_o.data.code);
return {
[k]: {
..._o,
data: { ..._o.data, ...(date ? { date } : {}) }
}
};
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you don't need the initial sequential keys the merge becomes much less verbose.
const
arr1 = [{ id: "abdc4051", date: "2017-01-24" }, { id: "abdc4052", date: "2017-01-22" }],
arr2 = [{ category: "Sport", data: { code: "abdc4051", name: "ab" } }, { category: "Others", data: { code: "abdc4052", name: "abc" } }],
dateMap = new Map(arr1.map(o => [o.id, o.date])),
result = arr2.map(o => (
{
...o,
data: { ...o.data, ...(dateMap.has(o.data.code) ? { date: dateMap.get(o.data.code) } : {}) }
}
));
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

JS how to return the dogs that match a select breed?

I am new to coding and cannot workout why my code is not working. Dose anyone have any suggestion of how to fix it?
The question I have been given is this;
This function takes an array of dog objects and returns an array of the names of all the pugs.
E.g. [
{name: 'Beatrice', breed: 'Lurcher'},
{name: 'Max', breed: 'Pug'},
{name: 'Poppy', breed: 'Pug'}
]
will return ['Max', 'Poppy']
This is the code I have written;
function getPugNames(dogs) {
let pugs = []
let reg = /(pug)/g
for (let i = 0; i < dogs.length; i ++) {
if(reg.test(dogs[i].bread)) {
pugs.push[i].name
}
} return pugs
}
My code will be run against this;
describe("getPugNames", () => {
it("returns [] when passed []", () => {
expect(getPugNames([])).to.eql([]);
});
it("returns an array of pug names when passed an array of dog objects", () => {
const dogs = [
{ name: "Beatrice", breed: "Lurcher" },
{ name: "Max", breed: "Pug" },
{ name: "Poppy", breed: "Pug" }
];
expect(getPugNames(dogs)).to.eql(["Max", "Poppy"]);
const dogs2 = [
{ name: "Steven", breed: "Lurcher" },
{ name: "Daphne", breed: "Pug" },
{ name: "Sandy", breed: "Labrador" },
{ name: "Mike", breed: "Pug" },
{ name: "Spike", breed: "Pug" }
];
expect(getPugNames(dogs2)).to.eql(["Daphne", "Mike", "Spike"]);
const dogs3 = [
{ name: "Kevin", breed: "Labrador" },
{ name: "Patch", breed: "Rottweiler" },
{ name: "Miles", breed: "Lurcher" },
{ name: "Sandy", breed: "Pug" },
{ name: "Spot", breed: "Pug" },
{ name: "Josephine", breed: "Terrier" },
{ name: "Eric", breed: "Pug" }
];
expect(getPugNames(dogs3)).to.eql(["Sandy", "Spot", "Eric"]);
});
});
This is the error that I am being given;
You just made some array of names, you need names of pugs, you can use filter your array like pugs.filter(p => p.breed === ‘pug’) this will give you an array with pug only elements(check filter documentation), than just take name from it using map, map transforms your array according to given callback function that accept array element and must return new element(check array.map)
pugs.push[i].name is a mistake. You should have pugs.push(dogs[i].name);.
Also, you don't really need a regex for pug. Just check like this:
if (dogs[i].breed.toLowerCase() === "pug")
You regular expression is /(pug)/g where it should be /(Pug)/g. But in my opinion if don't even need to use Regex. When it's direct comparison between strings you can use the comparison operator == or ===.
Other issue in your code it's how you are pushing to the array. Should be pugs.push(dogs[i].name)and not pugs.push[i].name. Therefore this is my suggestion:
function getPugNames(dogs) {
let pugs = []
for (let i = 0; i < dogs.length; i ++) {
if(dogs[i].bread === 'Pug') {
pugs.push(dogs[i].bread)
}
}
return pugs
}
I corrected your version and created an easier version for you. Here it goes:
//corrected version
function getPugNames(dogs) {
var pugs = [];
var reg = /pug/gi
for (let i = 0; i < dogs.length; i ++) {
reg.lastIndex = 0;
if (reg.test(dogs[i].breed))
pugs.push(dogs[i].name);
};
return pugs
}
//easier version:
var getPugNames2 = dogs=>dogs
.map(d=>d.breed.toLowerCase() == "pug" ? d.name : null)
.filter(e=>e);
const dogs1 = [
{ name: "Beatrice", breed: "Lurcher" },
{ name: "Max", breed: "Pug" },
{ name: "Poppy", breed: "Pug" }
];
const dogs2 = [
{ name: "Steven", breed: "Lurcher" },
{ name: "Daphne", breed: "Pug" },
{ name: "Sandy", breed: "Labrador" },
{ name: "Mike", breed: "Pug" },
{ name: "Spike", breed: "Pug" }
];
const dogs3 = [
{ name: "Kevin", breed: "Labrador" },
{ name: "Patch", breed: "Rottweiler" },
{ name: "Miles", breed: "Lurcher" },
{ name: "Sandy", breed: "Pug" },
{ name: "Spot", breed: "Pug" },
{ name: "Josephine", breed: "Terrier" },
{ name: "Eric", breed: "Pug" }
];
console.log(getPugNames([]));
console.log(getPugNames(dogs1));
console.log(getPugNames(dogs2));
console.log(getPugNames(dogs3));
console.log(getPugNames2([]));
console.log(getPugNames2(dogs1));
console.log(getPugNames2(dogs2));
console.log(getPugNames2(dogs3));
You had some errors.
First you have a typo on breed. You wrote 'bread' instead.
you have to set reg.lastIndex = 0 because regex, called several times may return different results
you had a syntax error on push,
regex must be case insensitive
Hope it helps you.
Within the code you wrote:
function getPugNames(dogs) {
let pugs = []
let reg = /(pug)/g
for (let i = 0; i < dogs.length; i ++) {
if(reg.test(dogs[i].bread)) {
pugs.push[i].name
}
} return pugs
}
You had some typos and errors. First off, you don't really need a regular expression to check the dog breed - see my if statement:
if (dogs[i].breed == "Pug") {...}
(You also had a typo - you spelled breed with an a, like bread.)
Secondly, your syntax for Array.prototype.push() is wrong - it should be this:
pugs.push(dogs[i].name);
So after you've done all that, your code should look like this:
function getPugNames(dogs) {
let pugs = [];
for (let i = 0; i < dogs.length; i++) {
if (dogs[i].breed == "Pug") {
pugs.push(dogs[i].name);
}
}
return pugs;
}
However, if you really wanted to make the code smaller and faster, you could use Array.prototype.filter() and ES6 arrow functions like so:
const getPugNames = (dogs) => dogs.filter(d => if (d.breed == "Pug") return d.name);

Array.filter() to remove duplicate Ojects

I would like to fuse Array.filter() function to remove duplicate objects
I am able to achieve in the case of string or integer arrays. But I am not able to achieve the same with array of objects as in the second case of names
const names = ['John', 'Paul', 'George', 'Ringo', 'John'];
let x = names => names.filter((v, i, arr) => arr.indexOf(v) === i);
console.log(x(names)); //[ 'John', 'Paul', 'George', 'Ringo' ]
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
// returns the same original array
Could you please help?
Using Array#reduce() and a Map accumulator then spread the values() of the Map into array
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
const unique = [... names.reduce((a,c)=>(a.set(c.name,c)),new Map).values()]
console.log(unique)
Use Array.reduce and Object.values
Iterate over the array and create an object with key as name and value as object from array. In case of objects with same name, the value will be overwritten in resultant object. Finally use Object.values to collect all the unique objects.
const names = [{ name: "John" },{ name: "Paul" },{ name: "George" },{ name: "Ringo" },{ name: "John" } ];
let result = Object.values(names.reduce((a,c) => Object.assign(a, {[c.name]:c}),{}));
console.log(result);
For tweaking - Plunker
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" }
];
/* unique => Filter: Remove all duplicate items from an array. Works with plain objects as well, since we stringify each array item.
* #type public Function
* #name unique
* #return Function( item )
* #notes
*/
const unique = () => {
const seen = {};
return item => {
const json = JSON.stringify( item );
return seen.hasOwnProperty( json )
? false
: ( seen[ json ] = true );
};
};
const result = names.filter( unique() );
console.log( result );
You could use lodash's _uniqBy for this:
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" } ];
const result = _uniqBy(names, 'name');
This can be done with the help of Sets as well
var names = [{ name: "John" },{ name: "Paul" },{ name: "George" },{ name: "Ringo" },{ name: "John" } ];
var result = Array.from(
names.reduce((s, d) => s.add(d.name), new Set)
, d => ({ name: d })
)
console.log(result)
Keith had a great suggestion to use findIndex with filter instead of indexOf. Object literals are always unique references, so we cannot compare them. We can however compare the name keys between the objects. We can do this with the aforementioned functions.
const names = [
{ name: "John" },
{ name: "Paul" },
{ name: "George" },
{ name: "Ringo" },
{ name: "John" }
];
console.log(names.filter(({name1}, i, a) => {
return i == a.findIndex(({name2}) => {
return name1 == name2;
});
});
const names = ['John', 'Paul', 'George', 'Ringo', 'John'];
function removeDups(names) {
let unique = {};
names.forEach(function(i) {
if(!unique[i]) {
unique[i] = true;
}
});
return Object.keys(unique);
}
removeDups(names); //'John', 'Paul', 'George', 'Ringo'

How to get an array of unique properties from an array of complex objects

I have an array of objects similar to
const array = [
{
documentId: "document1",
writers: [
{
name: "writer1",
date: "2017-12-11"
},
{
name: "writer2",
date: "2017-12-11"
}
]
},
{
documentId: "document2",
writers: [
{
name: "writer1",
date: "2017-12-11"
},
{
name: "writer3",
date: "2017-12-11"
}
]
},
{
documentId: "document3",
writers: [
{
name: "writer3",
date: "2017-12-11"
},
{
name: "writer4",
date: "2017-12-11"
}
]
},
I'm trying to extract all the unique writer's names and match them to all the documents they have written so that the final array looks something like this:
const finalArray = [
{name: "writter1", documents: ["document1", "document2"]},
{name: "writter2", documents: ["document1"]},
{name: "writter3", documents: ["document2", "document3"]},
{name: "writter4", documents: ["document3"]}
]
You can use Map to keep writers as keys then call reduce on your array to map documents to writers, then call values() on the Map object:
const ret = Array.from(array.reduce((acc, val) => {
val.writers.forEach(({ name }) => {
let w = acc.get(name) || { name: name, documents: [] };
w.documents = w.documents.concat(val.documentId);
acc.set(name, w);
});
return acc;
}, new Map()).values());
console.log(ret);
Maybe there will be a more elegant map-reduce solution. Anyway, this will works even if it's ugly:
const array = //your data
var output = []
for (let i = 0; i < array.length; i++)
for (let k = 0; k < array[i].writers.length; k++) {
let t = output.find(function(a){return array[i].writers[k].name === a.name})
if (t)
t.documents.push(array[i].documentId)
else
output.push({name: array[i].writers[k].name, documents: [array[i].documentId]})
}
console.log(output)
https://jsfiddle.net/50oph5g4/1/
You could take a Map which takes all names and the associated documents. If no map is avaliable for a name, then create a new entry.
A then end, get all objects of the map.
var array = [{ documentId: "document1", writers: [{ name: "writer1", date: "2017-12-11" }, { name: "writer2", date: "2017-12-11" }] }, { documentId: "document2", writers: [{ name: "writer1", date: "2017-12-11" }, { name: "writer3", date: "2017-12-11" }] }, { documentId: "document3", writers: [{ name: "writer3", date: "2017-12-11" }, { name: "writer4", date: "2017-12-11" }] }],
map = new Map,
result;
array.forEach(function (o) {
o.writers.forEach(function ({ name }) {
map.has(name) || map.set(name, { name, documents: [] });
map.get(name).documents.push(o.documentId);
});
});
result = Array.from(map.values());
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How do I access nested objects properties in console.table()?

Lets say I have the following array of objects:
var data = [
{ id: 123, author: { id: 123 } },
{ id: 123, author: { id: 123 } }
];
How can I populate a column in console.table with the id property of the author object?
This does not seem to work: console.table(data, ['id', 'author.id']);
I'm not sure you can do it with nested properties.
You could use map to pull the data out into a better format and then console.table it:
const data = [
{ id: 123, author: { id: 123 } },
{ id: 123, author: { id: 123 } }
];
const out = data.map(obj => {
return {
id: obj.id,
authorId: obj.author.id
};
});
console.table(out);
Note: you cannot hide the index column.

Categories

Resources