JS Turn an array into Object with property key/value - javascript

i was coding and i found this problem, the goal is turn the items array into a object with property key/value, counting the items that appear more than once like that:
{
cookie:{
MILK: 1,
CHOCOLATE: 2,
DELUXE: 1
},
bread:{
BIG: 2
},
beer:{
NEW: 1,
OLD: 1
}
}
I tried this code below
const items = [
"cookie-MILK",
"cookie-CHOCOLATE",
"cookie-CHOCOLATE",
"cookie-DELUXE",
"bread-BIG",
"bread-BIG",
"beer-NEW",
"beer-OLD"
]
let newArray = [];
items.forEach((e) => {
let splitArray = e.split("-");
newArray.push([splitArray[0], splitArray[1]]);
});
let result = newArray.reduce((acc, val) => {
if (!acc[val[0]] && !acc[val[1]] ) acc[val[0]] = {
[val[1]]: 1,
};
else acc[val[0]][val[1]]++;
return acc;
}, {});
But this code returns it and i don't know how to solve this question
{
cookie:{
MILK: 1,
CHOCOLATE: NaN,
DELUXE: NaN
},
bread:{
BIG: 2
},
beer:{
NEW: 1,
OLD: NaN
}
}

You could take a logical nullish assignment ??= for assigning an object or zero and increment the value.
const
items = ["cookie-MILK", "cookie-CHOCOLATE", "cookie-CHOCOLATE", "cookie-DELUXE", "bread-BIG", "bread-BIG", "beer-NEW", "beer-OLD"],
result = items.reduce((acc, val) => {
const [left, right] = val.split("-");
(acc[left] ??= {})[right] ??= 0;
acc[left][right]++;
return acc;
}, {});
console.log(result);

I think is beter solution:
const items = [
"cookie-MILK",
"cookie-CHOCOLATE",
"cookie-CHOCOLATE",
"cookie-DELUXE",
"bread-BIG",
"bread-BIG",
"beer-NEW",
"beer-OLD"
];
let res = {};
items.forEach(item => {
let itemParsed = item.split("-");
if(typeof res[itemParsed[0]] == "undefined")
res[itemParsed[0]] = {}
if(typeof res[itemParsed[0]][itemParsed[1]] == "undefined")
res[itemParsed[0]][itemParsed[1]] = 0;
res[itemParsed[0]][itemParsed[1]]++;
})
console.log(res)

Related

How do I create new object after manipulation

I have a JavaScript object like the following below availability and reserved, here I need to subtract quantity value from availability.
var availability = {"bike":10,"cycle":3,"car":1};
var reserved ={"cycle":1,"bike":10}
how should I get this response as below?
response = {"bike":0,"cycle":2,"car":1};
Why not a simple for loop.
var availability = { bike: 10, cycle: 3, car: 1 };
var reserved = { cycle: 1, bike: 10 };
let response = {};
for (let key in availability) {
if (reserved[key]) {
response[key] = availability[key] - reserved[key];
} else {
response[key] = availability[key];
}
}
console.log(response);
Output:
{ bike: 0, cycle: 2, car: 1 }
There are many way to solve this, but I recommend using reduce().
var availibilty = {
"bike": 10,
"cycle": 3,
"car": 1
};
var reserved = {
"cycle": 1,
"bike": 10
}
function calc(a, b) {
const answer = Object.keys(a).reduce((acc, key) => {
return {
...acc,
[key]: a[key] - (b[key] || 0)
}
}, {});
console.log(answer);
}
calc(availibilty, reserved);
You can iterate through each key-value pair and subtract quantity in availability with the corresponding key in reserved. Then create your result object using Object.fromEntries().
const availability = { "bike" : 10, "cycle" : 3, "car" : 1 },
reserved ={ "cycle": 1,"bike": 10 },
result = Object.fromEntries(Object.entries(availability).map(([key, value]) => [key, value - (reserved[key] ?? 0)]));
console.log(result);
You can loop through the Object. keys() of one object you provided and subtract the other using reduce() method.
var availibilty = {"bike":10,"cycle":3,"car":1};
var reserved ={"cycle":1,"bike":10}
let response = Object.keys(availibilty).reduce((x, y) => {
x[k] = availibilty[y] - reserved[y];
return x;
}, {});
console.log(response);
Please find Array.reduce implementation.
Logic
Loop through keys of availability object.
Find the values of each keys from reserved object.
Store the difference as the value for same key in the accumulator array.
var availability = { "bike": 10, "cycle": 3, "car": 1 };
var reserved = { "cycle": 1, "bike": 10 };
const response = Object.keys(availability).reduce((acc, curr) => {
acc[curr] = availability[curr] - (reserved[curr] || 0);
return acc;
}, {});
console.log(response);

Make a short version of JSON by merging the key value pairs

I have a json
input_lookup = [{"keyprefixname": "fruit","resultkey":"sweet" },
{"keyprefixname": "rate","resultkey":"ratex" }]
input = {
'fruit_a': "red apple"
'fruit_b': "green apple"
'rate_a': "10$"
'rate_b': "20$"
'vegetable_a': "spinach"
'vegetable_b': "carrot"
}
The input json has some prefixes listed in lookup and we need to merge the listed ones forming a new combined value json key pairs
the expected output is
result_output = {
'sweet': "red apple,green apple"
'ratex': "10$,20$"
'vegetable_a': "spinach" // not to combine this since it wont exist in lookup
'vegetable_b': "carrot"
}
I have tried with
result_output = {}
for(key in input_lookup){
if(key.indexOf(input_lookup) > -1)
key = key+ input_lookup[key]
}
There are several ways to do this. Here's a reducer, using Array.find to compare the lookup values to a value from the input:
const lookup = [
{prefix: "fruit", key: "sweet" },
{prefix: "rate", key: "ratex" },
];
const input = {
fruit_a: "red apple",
fruit_b: "green apple",
rate_a: "10$",
rate_b: "20$",
vegetable_a: "spinach",
vegetable_b: "carrot",
};
const reducedWithArrayOfValues = Object.entries(input)
.reduce( (acc, [key, value]) => {
const nwKey = lookup.find(v => key.startsWith(v.prefix));
return nwKey
? { ...acc, [nwKey.key]: (acc[nwKey.key] ||[]).concat(value) }
: { ...acc, [key]: value };
}, {}
);
const reducedWithStringValues = Object.entries(input)
.reduce( (acc, [key, value]) => {
const nwKey = lookup.find(v => key.startsWith(v.prefix));
return nwKey
? { ...acc, [nwKey.key]: `${acc[nwKey.key] ? `${
acc[nwKey.key]}#` : ""}${value}` }
: { ...acc, [key]: value };
}, {}
);
document.querySelector(`pre`).textContent =
JSON.stringify(reducedWithStringValues, null, 2);
document.querySelector(`pre`).textContent += `\n---\n${
JSON.stringify(reducedWithArrayOfValues, null, 2)}`;
<pre></pre>
here you go
function getAggregateKey(key, value) {
const result = input_lookup.find((item) => key.includes(item.keyprefixname));
if (result) {
return result["resultkey"];
}
return key;
}
const arrayObject = Object.entries(input).reduce((acc, cur) => {
const aggKey = getAggregateKey(cur[0]);
if (!(aggKey in acc)) {
acc[aggKey] = [];
}
acc[aggKey].push(cur[1])
return acc;
}, {});
const result = Object.entries(arrayObject).reduce((acc, cur) => {
acc[cur[0]] = cur[1].join(',');
return acc;
}, {});
console.log(result);
let input_lookup = [{
"keyprefixname": "fruit",
"resultkey": "sweet"
}, {
"keyprefixname": "rate",
"resultkey": "ratex"
}];
let input = {
'fruit_a': "red apple",
'fruit_b': "green apple",
'rate_a': "10$",
'rate_b': "20$",
'vegetable_a': "spinach",
'vegetable_b': "carrot"
};
// first we need a good lookup object the default is an array
// we made fruit > sweet and rate > ratex
// this is help later in the code
var good_lookup = {};
for(let i = 0; i < input_lookup.length ; i++){
let good_key = input_lookup[i]['keyprefixname'];
let good_val = input_lookup[i]['resultkey'];
good_lookup[good_key] = good_val;
}
let result_output = {};
for(let key in input ){
let to_lookup = key.split('_');
let to_lookup_key = to_lookup[0];//fruit, rate
var to_aggregate = good_lookup[to_lookup_key];
if(to_aggregate){
if(result_output[to_aggregate]){
result_output[to_aggregate] = result_output[to_aggregate] + ", " + input[key];
} else {
result_output[to_aggregate] = input[key];
}
} else {
result_output[key] = input[key];
}
}
console.log(result_output);
here is a fiddle for the code https://jsfiddle.net/z8usmgja/1/

React.js: How to find duplicates for properties in an array of object and put a progressive number on that field

I have an array of object and each object is for example :
const myArr=[{name:"john",id:1}{name:"john",id:2}{name:"mary",id:3}]
for the first 2 element for the property "name" I have the name "john" that is duplicate.
How can I modify the rendered names like that:
const myArr=[{name:"john (1 of 2)",id:1}{name:"john (2 of 2)",id:2}{name:"mary",id:3}]
Thanks in advance!
Reduce the input array into a map by name (i.e. group by name property), and map the array of values to the result array. If the group array has more than 1 element in it then sub-map the group to include the numbering. Flatten the overall result.
const myArr = [
{ name: "john", id: 1 },
{ name: "john", id: 2 },
{ name: "mary", id: 3 }
];
const res = Object.values(
myArr.reduce((groups, current) => {
if (!groups[current.name]) {
groups[current.name] = [];
}
groups[current.name].push(current);
return groups;
}, {})
).flatMap((value) => {
if (value.length > 1) {
return value.map((current, i, arr) => ({
...current,
name: `${current.name} (${i + 1} of ${arr.length})`
}));
}
return value;
});
console.log(res);
You can do use reduce(), filter(), and flat() and do this:
const myArr = [
{name:"john", id:1},
{name:"john", id:2},
{name:"mary", id:3}
]
const res = Object.values(myArr.reduce((acc, curr) => {
const total = myArr.filter(({ name }) => name === curr.name).length;
if(!acc[curr.name]) {
acc[curr.name] = [
{...curr}
]
} else {
const currentSize = acc[curr.name].length;
if(currentSize === 1) {
acc[curr.name][0].name = `${acc[curr.name][0].name} (1 of ${total})`
}
acc[curr.name].push({
...curr,
name: `${curr.name} (${currentSize + 1} of ${total})`
})
}
return acc;
}, {})).flat();
console.log(res);
const myArr = [{name:"john",id:1}, {name:"john",id:2}, {name:"mary",id:3}];
const namesArray = myArr.map(elem => elem.name);
const namesTraversed = [];
let currentCountOfName = 1;
let len = 0;
myArr.forEach(elem => {
len = namesArray.filter(name => name === elem.name).length;
if (len > 1) {
if (namesTraversed.includes(elem.name)) {
namesTraversed.push(elem.name);
currentCountOfName = namesTraversed.filter(name => name === elem.name).length;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
} else {
namesTraversed.push(elem.name);
currentCountOfName = 1;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
}
}
});
console.log(myArr);
Check if this helps you
const myArr = [{
name: "john",
id: 1
}, {
name: "john",
id: 2
}, {
name: "mary",
id: 3
}]
// to keep a track of current copy index
let nameHash = {}
const newMyArr = myArr.map(ele => {
const noOccurence = myArr.filter(obj => obj.name ===ele.name).length;
if(noOccurence > 1){
// if there are multiple occurences get the current index. If undefined take 1 as first copy index.
let currentIndex = nameHash[ele.name] || 1;
const newObj = {
name: `${ele.name} (${currentIndex} of ${noOccurence})`,
id: ele.id
}
nameHash[ele.name] = currentIndex+ 1;
return newObj;
}
return ele;
})
console.log(newMyArr);

Convert an array to json object by javascript

I am stuck to solve this problem.
Convert an array below
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
to json Object
var expectedResult = {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
Which data structure and algorithm can I apply for it?
Thanks
You need to first split each element to convert to array
using reverse reduce method you can convert them to object.
And your last step is merge this objects.
Lodash.js merge method is an one way to merge them.
var input = ['animal/mammal/dog','animal/mammal/cat/tiger','animal/mammal/cat/lion', 'animal/mammal/elephant','animal/reptile', 'plant/sunflower']
var finalbyLodash={}
input.forEach(x=>{
const keys = x.split("/");
const result = keys.reverse().reduce((res, key) => ({[key]: res}), true);
finalbyLodash = _.merge({}, finalbyLodash, result);
});
console.log(finalbyLodash);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
To make the process more understandable, break the problem down into pieces.
The first step is convert each string into something we can use, converting this:
"animal/mammal/dog"
into this:
[ "animal", "mammal", "dog" ]
That's an array of property names needed to build the final object.
Two functions will accomplish this for you, String.prototype.split() to split the string into an array, and Array.prototype.map() to transform each of the array elements:
let splitIntoNames = input.map(str => str.split('/'));
The intermediate result is this:
[
[ "animal", "mammal", "dog" ],
[ "animal", "mammal", "cat", "tiger" ],
[ "animal", "mammal", "cat", "lion" ],
[ "animal", "mammal", "elephant" ],
[ "animal", "reptile" ],
[ "plant", "sunflower" ]
]
Next step is to iterate over each array, using Array.prototype.forEach() to add properties to the object. You could add properties to the object with a for loop, but let's do that with a recursive function addName():
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
The result:
result: {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
const input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/mammal/elephant",
"animal/reptile",
"plant/sunflower",
];
let splitIntoNames = input.map((str) => str.split("/"));
console.log("splitIntoNames:", JSON.stringify(splitIntoNames, null, 2));
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
console.log("result:", JSON.stringify(result, null, 2));
You can create a function that will slice every element from the array by "/" than you put the results into a variable and than just mount the Json. I mean something like that below:
window.onload = function() {
var expectedResult;
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
input.forEach(element => {
var data = element.split('/');
var dog = data[2] === 'dog' ? true : false
var tiger = data[2] === 'cat' && data[3] === 'tiger' ? true : false
var lion = data[2] === 'cat' && data[3] === 'lion' ? true : false
expectedResult = {
data[0]: {
data[1]: {
"dog": dog,
"cat": {
"tiger": tiger,
"lion": lion
}
}
}
}
})
}
Late to the party, here is my try. I'm implmenting recursive approach:
var input = ['animal/mammal/dog', 'animal/mammal/cat/tiger', 'animal/mammal/cat/lion', 'animal/mammal/elephant', 'animal/reptile', 'plant/sunflower'];
result = (buildObj = (array, Obj = {}) => {
array.forEach((val) => {
keys = val.split('/');
(nestedFn = (object) => {
outKey = keys.shift();
object[outKey] = object[outKey] || {};
if (keys.length == 0) object[outKey] = true;
if (keys.length > 0) nestedFn(object[outKey]);
})(Obj)
})
return Obj;
})(input);
console.log(result);
I try with array reduce, hope it help
let input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/elephant",
"animal/reptile",
"plant/sunflower",
];
let convertInput = (i = []) =>
i.reduce((prev, currItem = "") => {
let pointer = prev;
currItem.split("/").reduce((prevPre, currPre, preIdx, arrPre) => {
if (!pointer[currPre]) {
pointer[currPre] = preIdx === arrPre.length - 1 ? true : {};
}
pointer = pointer[currPre];
}, {});
return prev;
}, {});
console.log(JSON.stringify(convertInput(input), null, 4));

How to concatenate object values with same id

I have an array:
let ar = [
{
uid:1,
flat_no: 1
},
{
uid:2,
flat_no: 2
},
{
uid:1,
flat_no:3
}
];
If uid are same then I want to remove duplicate uid and concatenate its flat_no. The output array should be like this:
[
{
uid:1,
flat_no: [1,3]
},
{
uid:2,
flat_no: 2
}
];
You can use a combination of Array.reduce and Array.find.
If you find an existing item in your accumulator array, just update it's flat_no property, otherwise push it to the accumulator array.
let arr = [
{
uid: 1,
flat_no: 1
},
{
uid: 2,
flat_no: 2
},
{
uid: 1,
flat_no: 3
}
]
arr = arr.reduce((arr, item) => {
const existing = arr.find(innerItem => innerItem.uid === item.uid)
if (existing) {
existing.flat_no = Array.isArray(existing.flat_no)
? existing.flat_no
: [existing.flat_no]
existing.flat_no.push(item.flat_no)
} else {
arr.push(item)
}
return arr
}, [])
console.log(arr)
You can iterate over your array and fill an object (used as a hashmap here).
Once done, you extract the values to get your result.
let hashResult = {}
ar.forEach(element => {
if (hashResult[element.uid] == undefined) {
hashResult[element.uid] = { uid: element.uid, flat_no: [] }
}
hashResult[element.uid].flat_no.push(element.flat_no)
})
let result = Object.values(hashResult)
console.log(new Date(), result)
You can do this in a concise way with a single Array.reduce and Object.values to match your desired output:
let data = [ { uid:1, flat_no: 1 }, { uid:2, flat_no: 2 }, { uid:1, flat_no:3 } ];
const result = data.reduce((r, {uid, flat_no}) => {
r[uid] ? r[uid].flat_no = [r[uid].flat_no, flat_no] : r[uid] = {uid, flat_no}
return r
}, {})
console.log(Object.values(result))
1)Reduce the initial array to an object which has uid as the key and the flat_no as the value.
2)Then run a map on the keys to convert it into an array of objects with uid and flat_no.
1) First Step Code
let ar = [{uid:1, flat_no: 1},{uid:2, flat_no: 2},{uid:1, flat_no:3}];
let outputObj = ar.reduce((outputObj,currObj,currIndex) => {
let {uid,flat_no} = currObj
if (outputObj[uid]) {
outputObj[uid].push(flat_no)
}
else {
outputObj[uid] = [flat_no]
}
return outputObj
},{})
2)
let finalOutput = Object.keys(outputObj).map(key =>
({uid:key,flat_no:outputObj[key]}))
console.log(finalOutput)

Categories

Resources