I need to convert this object
{
person1_name: "John",
person0_name: "Rob",
person1_age: 36,
person0_age: 45,
total: 2,
}
into this format
{
mambers: [
{
name: "Rob",
age: 45,
},
{
name: "John",
age: 36,
},
],
total: 2,
}
Does anyone know how to do it in not to complicated way using JavaScript?
Following is one of the way.
const x={
person1_name: 'John',
person0_name: 'Rob',
person1_age: 36,
person0_age: 45,
total: 2
}
const extractKey = keyName => obj => Object.keys(obj).filter(key => key.includes(keyName))
const names = extractKey('_name')(x);
const ages = extractKey('_age')(x);
const transform = (names, ages) => obj => ({ members: names.map((key, index) => ({name:obj[key], age: obj[ages[index]]})), total:names.length})
console.log(transform(names, ages)(x))
Asuming that there exists for every 0, 1, ... total-1 an entry for name and age you can use this:
let data = {
person1_name: "John",
person0_name: "Rob",
person1_age: 36,
person0_age: 45,
total: 2,
};
let result = {members: [], total: data.total};
for (let i=0; i<data.total; i++) {
result.members.push({
name: data['person' + i + '_name'],
age: data['person' + i + '_age'],
});
}
console.log(result);
Assuming all the keys are in the format of 'person{index}_{name}', i.e. 'person0_name', a regex approach can be taken, as such:
var input = {
person1_name: "John",
person0_name: "Rob",
person1_age: 36,
person0_age: 45,
total: 2,
};
function transform(input) {
var output = {};
var members = {};
var keys = Object.keys(input);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var match = key.match(/person(.*[^_])_(.*)/);
if (!match) {
output[key] = input[key];
continue;
}
var member = members[match[1]] || {};
member[match[2]] = input[key];
members[match[1]] = member;
}
output.members = Object.keys(members).map((k) => members[k]);
return output;
}
console.log(transform(input));
This function can accommodate more than just 'name' and 'age', so if additional properties need transforming this will work.
A solution not requiring contiguous numbering:
var input = {
person1_name: "John",
person0_name: "Rob",
person1_age: 36,
person0_age: 45,
total: 2,
}
// match N from personN_name, using lookbehind and lookahead to match only the number
// use "optional chaining index" ?.[0] to extract the first match is found
const match = key => key.match(/(?<=^person)\d+(?=_name$)/)?.[0]
// "functional" approach
// extract keys from input, map them with the matching regexp and filter actual matches
var ids = Object.keys(input).map(k => match(k)).filter(Boolean)
// map ids to {name,age} objects
var members = ids.map(id => ({name:input[`person${id}_name`],age:input[`person${id}_age`]}))
// construct output
var output = {total:input.total,members}
console.log(output)
// "iterative" pproach
// initial value of outpit
var output = {total:input.total,members:[]}
for (var [k,v] of Object.entries(input)) { //for each key-value from input
var id = match(k) // try to get key
if (!id) continue // if id not found, continue to next kev-value pair
var name = v // the match is against personN_name, so v is the name
var age = input[`person${id}_age`] // get age
output.members.push({name,age}) // push new member
}
console.log(output)
Related
I have to compare two array of objects and check if the same item includes in the other array.
const array1 = [
{ item: "orange", id: 11 },
{ item: "apple", id: 12 },
];
const array2 = [10, 11, 12];
If I am checking with a value from array2 in array1.How can I get output like below when mapping array2?
Item does'nt exists
orange
apple
Here's a way using Map, though with a bit of tweaking it could use a normal object instead of Map. The map indexes the items in array1 by id and then allows you to look for the item in the map (using has() or get()); if it doesn't exist you can fall back to the default string. ?? is the nullish coalescing operator and it allows you to give a term for the expression should the value before ?? be null or undefined.
const array1 = [{ item: "orange", id: 11 }, { item: "apple", id: 12 }];
const array2 = [10, 11, 12];
const default_string = "Item does'nt exists";
const array1_map = new Map(array1.map((o) => [o.id, o]));
const res = array2.map( (id) => array1_map.get(id)?.item ?? default_string );
console.log(res);
Try this
const array1 = [{
item: 'orange',
id: 11
}, {
item: 'apple',
id: 12
}]
const array2 = [10, 11, 12]
for (const x of array2) {
//find element from array
const searchElem = array1.find((item) => item.id == x)
if (searchElem) {
console.log(searchElem.item + " for " + x)
} else {
console.log("Item doesn't exists for", x)
}
}
You can easily achieve this result using map and find
const array1 = [
{ item: "orange", id: 11 },
{ item: "apple", id: 12 },
];
const array2 = [10, 11, 12];
const result = array2.map((id) => {
const itemFound = array1.find((o) => o.id === id);
if (itemFound) return `${itemFound.item} for ${itemFound.id}`;
else return `Item does'nt exists for 10`;
});
console.log(result);
The easiest way to get common items by comparing two array in JavaScript is using filter() and includes() array functions.
For example:
const array1 = [
{ item: "orange", id: 11 },
{ item: "apple", id: 12 },
];
const array2 = [10, 11, 12];
const matchedArray = array1.filter((item) => array2.includes(item.id));
console.log(matchedArray);
We don't need to use for loop, forEach, map and find functions.
Try this code I think it will solve your problem
I have written some comments on javascript code it may help you.
const array1=[{item:'orange', id:11},{item:'apple', id:12}]
const array2=[10,11,12]
function removeDuplicates(array, matchKey) {
return array.filter((value, index) => {
return array.indexOf(array.find(value_1 => value_1[matchKey] == value[matchKey])) == index
});
}
// send "id" parameter if you want to filter array by id
// ex: removeDuplicates(array1, 'id')
const filteredArray1 = removeDuplicates(array1, 'item');
array2.forEach(id => {
let foundItem = array1.find(itemObj => itemObj.id == id);
if(foundItem == null) {
console.log(`Item doesn't exists for ${id}`);
}else {
console.log(`${foundItem.item} for ${id}`);
}
});
If I understand the question correctly what you want to do is confirm if an object with a certain property exists in Array 1 for each element in Array 2.
If you want to check each and see if it exists you can do this:
const fruits = [
{item: 'orange', id: 11},{item: 'apple', id: 12}
]
const fruitIds = fruits.map((fruit) => fruit.id);
const ids = [10, 11, 12]
ids.forEach((id) => {
console.log(`${id} exists in fruits: ` + fruitIds.includes(id))
})
Or if you wish to check if there is a fruit for each ID in the array and you only care about true / false if all exist or not then you can do:
const fruits = [
{item: 'orange', id: 11},
{item: 'apple', id: 12}
]
const fruitIds = fruits.map((fruit) => fruit.id).sort();
const ids = [10, 11, 12];
console.log("There is a fruit for each ID in ID array: ", JSON.stringify(ids) === JSON.stringify(fruitIds))
If this does not answer your question then please edit and try to make your question clearer and I'll do the same with my answer.
Note that the last snippet is just one way to compare arrays or objects in JavaScript.
var values =selectValues;
var names = selectNames;
var priorities = prioritizedHours;
var prefers = preferHrsArray;
var years = workedYearsArray;
var items = values.map((value, index) => {
return {
value: value,
name: names[index],
priority: priorities[index],
prefer: prefers[index],
year: years[index]
}
});
var arrayObject = JSON.stringify(items);
Logger.log('Object array: '+arrayObject);
In the above program, I am creating an object from the arrays such as names, priorities, and so on. Resulting Object is following after I have made a sorting of them:
[
{"value":1,"name":"Fiona","prefer":30,"year":6},
{"value":1,"name":"Martin","prefer":40,"year":7},
{"value":2,"name":"Adam","prefer":0,"year":20},
{"value":2,"name":"Steve","prefer":100,"year":5}
]
Now as sorting is done, I want the arrays back as they are in the Object.
I am trying to get arrays like:
value = [1,1,2,2],
name = ['Fiona', 'Martin','Adam', 'Steve'],
prefer = [30,40,0,100],
year = [6,7,20,5]
Thank you for helping me out.
You can use forEach for this case
const array = [
{"value":1,"name":"Fiona","prefer":30,"year":6},
{"value":1,"name":"Martin","prefer":40,"year":7},
{"value":2,"name":"Adam","prefer":0,"year":20},
{"value":2,"name":"Steve","prefer":100,"year":5}
]
const values = []
const names = []
const prefers = []
const years = []
array.forEach(rec => {
values.push(rec.value),
names.push(rec.name),
prefers.push(rec.prefer),
years.push(rec.year)
})
console.log(values)
console.log(names)
console.log(prefers)
console.log(years)
Map should work:
const data = [
{ value: 1, name: "Fiona", prefer: 30, year: 6 },
{ value: 1, name: "Martin", prefer: 40, year: 7 },
{ value: 2, name: "Adam", prefer: 0, year: 20 },
{ value: 2, name: "Steve", prefer: 100, year: 5 },
];
const values = data.map(x=>x.value);
const names = data.map(x=>x.name);
console.log(values, names);
//[ 1, 1, 2, 2 ] [ 'Fiona', 'Martin', 'Adam', 'Steve' ]
See MDN for details of map
You could also make it a little more dynamic by using reduce and then only getting the lists you want using Object destructuring.
const arr = [
{"value":1,"name":"Fiona","prefer":30,"year":6},
{"value":1,"name":"Martin","prefer":40,"year":7},
{"value":2,"name":"Adam","prefer":0,"year":20},
{"value":2,"name":"Steve","prefer":100,"year":5}
];
const {name, value, prefer, year} = arr.reduce((acc, curr) => {
Object.entries(curr).forEach(([key, val]) => {
if(acc[key] == null)
acc[key] = [];
acc[key].push(val);
});
return acc;
}, {})
console.log(name);
console.log(value);
console.log(prefer);
console.log(year);
I'm trying to create an array that contains objects with an id and amount, grouped by id. The ids needs to be unique. So if there is 2 objects with same id, the amount will be added.
I can do it with nested for-loops, but I find this solution inelegant and huge. Is there a more efficient or cleaner way of doing it?
var bigArray = [];
// big Array has is the source, it has all the objects
// let's give it 4 sample objects
var object1 = {
id: 1,
amount: 50
}
var object2 = {
id: 2,
amount: 50
}
var object3 = {
id: 1,
amount: 150
}
var object4 = {
id: 2,
amount:100
}
bigArray.push(object1,object2,object3,object4);
// organizedArray is the array that has unique ids with added sum. this is what I'm trying to get
var organizedArray = [];
organizedArray.push(object1);
for(var i = 1; i < bigArray.length; i++ ) {
// a boolean to keep track whether the object was added
var added = false;
for (var j = 0; j < organizedArray.length; j++){
if (organizedArray[j].id === bigArray[i].id) {
organizedArray[j].amount += bigArray[i].amount;
added = true;
}
}
if (!added){
// it has object with new id, push it to the array
organizedArray.push(bigArray[i]);
}
}
console.log(organizedArray);
You can definitly make it cleaner and shorter by using reduce, not sure about efficiency though, i would say a traditional for loop is more efficient :
var bigArray = [];
var object1 = {id: 1, amount: 50}
var object2 = {id: 2, amount: 50}
var object3 = {id: 1, amount: 150}
var object4 = {id: 2, amount: 100}
bigArray.push(object1, object2, object3, object4);
var organizedArray = bigArray.reduce((acc, curr) => {
// check if the object is in the accumulator
const ndx = acc.findIndex(e => e.id === curr.id);
if(ndx > -1) // add the amount if it exists
acc[ndx].amount += curr.amount;
else // push the object to the array if doesn't
acc.push(curr);
return acc;
}, []);
console.log(organizedArray)
Rather than an organized array, how about a single object whose keys are the ids and values are the sums.
var bigArray = [
{ id: 1, amount: 50 },
{ id: 2, amount: 50 },
{ id: 1, amount: 150 },
{ id: 2, amount: 100 }
];
let total = {}
bigArray.forEach(obj => {
total[obj.id] = (total[obj.id] || 0) + obj.amount;
});
console.log(total);
If you really need to convert this to an array of objects then you can map the keys to objects of your choosing like this:
var bigArray = [
{ id: 1, amount: 50 },
{ id: 2, amount: 50 },
{ id: 1, amount: 150 },
{ id: 2, amount: 100 }
];
let total = {}
bigArray.forEach(obj => {
total[obj.id] = (total[obj.id] || 0) + obj.amount;
});
console.log(total);
// If you need the organized array:
let organizedArray = Object.keys(total).map(key => ({ id: key, amount: total[key] }));
console.log(organizedArray);
function getUniqueSums(array) {
const uniqueElements = [];
const arrayLength = array.length;
for(let index = 0; index < arrayLength; index++) {
const element = array[index];
const id = element.id;
const uniqueElement = findElementByPropertyValue(uniqueElements, 'id', id);
if (uniqueElement !== null) {
uniqueElement.amount += element.amount;
continue;
}
uniqueElements.push(element);
}
return uniqueElements;
}
function findElementByPropertyValue(array, property, expectedValue) {
const arrayLength = array.length;
for(let index = 0; index < arrayLength; index++) {
const element = array[index];
const value = element[property];
if (value !== expectedValue) {
continue;
}
return element;
}
return null;
}
This is an untested code. You will be able to understand the logic. Logic is almost same yours. But, perhaps a more readable code.
how to count the value of object in new object values
lets say that i have json like this :
let data = [{
no: 3,
name: 'drink'
},
{
no: 90,
name: 'eat'
},
{
no: 20,
name: 'swim'
}
];
if i have the user pick no in arrays : [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
so the output should be an array
[
{
num: 3,
total: 11
},
{
num: 90,
total: 1
},
{
num:20,
total: 4
}
];
I would like to know how to do this with a for/of loop
Here is the code I've attempted:
let obj = [];
for (i of arr){
for (j of data){
let innerObj={};
innerObj.num = i
obj.push(innerObj)
}
}
const data = [{"no":3,"name":"drink"},{"no":90,"name":"eat"},{"no":20,"name":"swim"}];
const arr = [3,3,3,3,3,3,3,3,3,3,3,20,20,20,20,80,80];
const lookup = {};
// Loop over the duplicate array and create an
// object that contains the totals
for (let el of arr) {
// If the key doesn't exist set it to zero,
// otherwise add 1 to it
lookup[el] = (lookup[el] || 0) + 1;
}
const out = [];
// Then loop over the data updating the objects
// with the totals found in the lookup object
for (let obj of data) {
lookup[obj.no] && out.push({
no: obj.no,
total: lookup[obj.no]
});
}
document.querySelector('#lookup').textContent = JSON.stringify(lookup, null, 2);
document.querySelector('#out').textContent = JSON.stringify(out, null, 2);
<h3>Lookup output</h3>
<pre id="lookup"></pre>
<h3>Main output</h3>
<pre id="out"></pre>
Perhaps something like this? You can map the existing data array and attach filtered array counts to each array object.
let data = [
{
no: 3,
name: 'drink'
},
{
no:90,
name: 'eat'
},
{
no:20,
name: 'swim'
}
]
const test = [3,3,3,3,3,3,3,3,3,3,3,90,20,20,20,20]
const result = data.map((item) => {
return {
num: item.no,
total: test.filter(i => i === item.no).length // filters number array and then checks length
}
})
You can check next approach using a single for/of loop. But first I have to create a Set with valid ids, so I can discard noise data from the test array:
const data = [
{no: 3, name: 'drink'},
{no: 90, name: 'eat'},
{no: 20, name: 'swim'}
];
const userArr = [3,3,3,3,3,3,3,3,7,7,9,9,3,3,3,90,20,20,20,20];
let ids = new Set(data.map(x => x.no));
let newArr = [];
for (i of userArr)
{
let found = newArr.findIndex(x => x.num === i)
if (found >= 0)
newArr[found].total += 1;
else
ids.has(i) && newArr.push({num: i, total: 1});
}
console.log(newArr);
I want to transform this to an array of objects ordered based on an array of keys:
{
tom: 11,
jim: 22,
jay: 13
}
Input -> Output examples:
['jim', 'tom', 'kim', 'jay'] -> [{jim: 22}, {tom: 11}, {jay: 13}]
['may', 'jay', 'tom', 'jim'] -> [{jay: 13}, {tom: 11}, {jim: 22}]
How can I accomplish this? I'd rather a one line lodash solution.
For what it is worth, here's a JS function that performs what you want.
function transform(targetObj, keyArray) {
let resultArray = [];
// Sanity (may want to throw error here)
if (!targetObj || !keyArray) { return resultArray; }
for (let i = 0; i < keyArray.length; i++) {
if (!targetObj.hasOwnProperty(keyArray[i])) { continue; }
let item = {};
item[keyArray[i]] = targetObj[keyArray[i]];
resultArray.push(item);
}
return resultArray;
}
Tests
let obj = { tom: 11, jim: 22, jay: 13 };
let input1 = ['jim', 'tom', 'kim', 'jay'];
let input2 = ['may', 'jay', 'tom', 'jim'];
let result1 = transform(obj, input1);
console.log(JSON.stringify(result1));
let result2 = transform(obj, input2);
console.log(JSON.stringify(result2));
JSFiddle
Assuming the object is named obj and the list of keys to look up is named keys:
_.zip([keys, keys.map(x => obj[x])]).filter(([k, v]) => v).map(x => _.fromPairs([x]))
Or, if you don't care about order, there's another way:
_.toPairs(obj).filter(([k, v]) => _.include(keys, k)).map(x => _.fromPairs([x]))
A one-liner lodash solution would be to use lodash#toPairs to convert the object into an array of key-value pairs, lodash#chunk to wrap each pairs with another array as preparation for mapping each item to form the pairs into an object using lodash#map with a lodash#fromPairs iteratee.
var result = _(data).toPairs().chunk().map(_.fromPairs).value();
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = _(data).toPairs().chunk().map(_.fromPairs).value();
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
An Vanilla JS ES6 solution would be to use Object#keys to get an array of keys from the object, Array#map to map each keys to associate each key to form an array of objects. We used the ES6 computed property names feature to associate the keys directly into an anonymous object.
var result = Object.keys(data).map(key => ({ [key]: data[key] }));
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = Object.keys(data).map(key => ({ [key]: data[key] }));
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
If the browsers that you use doesn't support ES6 then you can simply convert the solution above into this:
var result = Object.keys(data).map(function(key) {
var object = {};
object[key] = data[key];
return object;
});
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = Object.keys(data).map(function(key) {
var object = {};
object[key] = data[key];
return object;
});
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
Basically for a one liner solution to this you don't need lodash, just simple filter and map would be enough, however if you want you can use lodash.
//this is your source object
var keys = {
tom: 11,
jim: 22,
jay: 13
}
Now, Lets assume you have 2 (some) arrays
var input1 = ['jim', 'tom', 'kim', 'jay'];
var input2 = ['may', 'jay', 'tom', 'jim'];
And here we go:
//for first input
input1.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
//for secondinput
input2.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
Here is a working snippet for you:
var keys = {
tom: 11,
jim: 22,
jay: 13
}
var input1 = ['jim', 'tom', 'kim', 'jay'];
var input2 = ['may', 'jay', 'tom', 'jim'];
var output1 = input1.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
var output2 = input2.filter(s=>keys [s]).map(s=> ({[s]: keys[s]}));
console.log("Output1: ", JSON.stringify(output1));
console.log("Output2: ", JSON.stringify(output2));