I have an array of objects with example values
[
{name:"Name1",date:"2018-08-01", optimalValue:"33", realValue:"55"},
{name:"Name2",date:"2018-08-03", optimalValue:"17", realValue:"23"},
{name:"Name3",date:"2018-08-01", optimalValue:"23", realValue:"12"},
{name:"Name4",date:"2018-08-04", optimalValue:"12", realValue:"11"},
]
I want to find in this array element with same date and sum values in optimalValue and realValue and have similar array like this:
[
{date:"2018-08-01", optimalValue:"56", realValue:"77"},
{date:"2018-08-03", optimalValue:"17", realValue:"23"},
{date:"2018-08-04", optimalValue:"12", realValue:"11"},
]
Just use a hashtable to find / group duplicates:
const hash = {}, result = [];
for(const { date, name, optimalValue, realValue } of input) {
if(!hash[date])
result.push(hash[date] = { date, name, optimalValue: 0, realValue: 0 });
hash[date].realValue +=+ realValue;
hash[date].optimalValue +=+ optimalValue;
}
You can use the function reduce for grouping and sum the values and the function Object.values to extract the desired array.
let array = [{name:"Name1",date:"2018-08-01", optimalValue:"33", realValue:"55"},{name:"Name2",date:"2018-08-03", optimalValue:"17", realValue:"23"},{name:"Name3",date:"2018-08-01", optimalValue:"23", realValue:"12"},{name:"Name4",date:"2018-08-04", optimalValue:"12", realValue:"11"},],
result = Object.values(array.reduce((a, {name, date, optimalValue, realValue}) => {
a[date] = (a[date] || {date, optimalValue: 0, realValue: 0});
a[date].realValue = String(Number(a[date].realValue) + Number(realValue));
a[date].optimalValue = String(Number(a[date].optimalValue) + Number(optimalValue));
return a;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.reduce() for that. Since you require optimalValue and realValue as a string type, you can convert those into string after summing up the value using parseInt():
var arr = [
{name:"Name1",date:"2018-08-01", optimalValue:"33", realValue:"55"},
{name:"Name2",date:"2018-08-03", optimalValue:"17", realValue:"23"},
{name:"Name3",date:"2018-08-01", optimalValue:"23", realValue:"12"},
{name:"Name4",date:"2018-08-04", optimalValue:"12", realValue:"11"},
];
var res = arr.reduce((acc, obj)=>{
var existObj = acc.find(item => item.date === obj.date);
if(existObj){
existObj.realValue = (parseInt(existObj.realValue) + parseInt(obj.realValue)).toString();
existObj.optimalValue = (parseInt(existObj.optimalValue) + parseInt(obj.optimalValue)).toString();
return acc;
}
acc.push(obj);
return acc;
},[]);
console.log(res);
Related
I would like to get find elements having same characters but in different order in an array. I made javascript below,is there any way to create Javascript function more basic? Can you give me an idea? Thank you in advance..
<p id="demo"></p>
<script>
const arr1 = ["tap", "pat", "apt", "cih", "hac", "ach"];
var sameChars = 0;
var subArr1 = [];
for(var i = 0; i < arr1.length; i++){
for(var j = i+1; j < arr1.length; j++){
if(!subArr1.includes(arr1[i]) && !subArr1.includes(sortAlphabets(arr1[i]))){
subArr1.push(arr1[i]);
sameChars++;
}
if(sortAlphabets(arr1[i]) == sortAlphabets(arr1[j])){
if(!subArr1.includes(arr1[j])){
subArr1.push(arr1[j]);
}
}
}
}
function sortAlphabets(text1) {
return text1.split('').sort().join('');
};
document.getElementById("demo").innerHTML = sameChars;
</script>
I would just use reduce. Loop over split the string, sort it, join it back. Use it as a key in an object with an array and push the items onto it.
const arr1 = ["tap", "pat", "apt", "cih", "hac", "ach"];
const results = arr1.reduce((obj, str) => {
const key = str.split('').sort().join('');
obj[key] = obj[key] || [];
obj[key].push(str);
return obj;
}, {});
console.log(Object.values(results));
You can get the max frequency value by building a map and getting the max value of the values.
const frequencyMap = (data, keyFn) =>
data.reduce(
(acc, val) =>
(key => acc.set(key, (acc.get(key) ?? 0) + 1))
(keyFn(val)),
new Map());
const groupMap = (data, keyFn) =>
data.reduce(
(acc, val) =>
(key => acc.set(key, [...(acc.get(key) ?? []), val]))
(keyFn(val)),
new Map());
const
data = ["tap", "pat", "apt", "cih", "hac", "ach"],
sorted = (text) => text.split('').sort().join(''),
freq = frequencyMap(data, sorted),
max = Math.max(...freq.values()),
groups = groupMap(data, sorted);
document.getElementById('demo').textContent = max;
console.log(Object.fromEntries(freq.entries()));
console.log(Object.fromEntries(groups.entries()));
.as-console-wrapper { top: 2em; max-height: 100% !important; }
<div id="demo"></div>
Maybe split the code into two functions - one to do the sorting and return a new array, and another to take that array and return an object with totals.
const arr = ['tap', 'pat', 'apt', 'cih', 'hac', 'ach'];
// `sorter` takes an array of strings
// splits each string into an array, sorts it
// and then returns the joined string
function sorter(arr) {
return arr.map(str => {
return [...str].sort().join('');
});
}
// `checker` declares an object and
// loops over the array that `sorter` returned
// creating keys from the strings if they don't already
// exist on the object, and then incrementing their value
function checker(arr) {
const obj = {};
for (const str of arr) {
// All this line says is if the key
// already exists, keep it, and add 1 to the value
// otherwise initialise it with 0, and then add 1
obj[str] = (obj[str] || 0) + 1;
}
return obj;
}
// Call `checker` with the array from `sorter`
console.log(checker(sorter(arr)));
<p id="demo"></p>
Additional documentation
map
Loops and iteration
Spread syntax
This question already has answers here:
Create an object based on file path string
(3 answers)
Closed 1 year ago.
I have an array of structured strings with have connection | as a format which self-divided into levels. I want to convert it into a structured object with multiple levels.
Input:
[
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
Expected output:
{
clothes: {
tshirt: {
tshirt-for-kids: {},
tshirt-for-men: {
luxury-tshirt: {}
}
},
coat: {
raincoat: {}
leather-coat: {}
}
}
}
Very simple task - just enumerate the array and create the relevant object keys:
var myArray = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
var result = {}, levels, current, temp;
while(myArray.length > 0)
{
levels = myArray.pop().split('|');
temp = result;
while(levels.length > 0)
{
current = levels.shift();
if(!(current in temp)) temp[current] = {};
temp = temp[current];
}
}
console.log(result);
You could try this:
const input = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
];
function convertStrToObject(str, sep, obj) {
const sepIndex = str.indexOf(sep);
if (sepIndex == -1) {
obj[str] = obj[str] || {};
} else {
const key = str.substring(0, sepIndex);
obj[key] = obj[key] || {};
convertStrToObject(str.substring(sepIndex + 1), sep, obj[key]);
}
}
const all = {};
for (let i = 0; i < input.length; ++i) {
convertStrToObject(input[i], "|", all);
}
console.log(all);
Assuming you intend to collect properties, all having an empty object as leaf node.
// input
const input = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
];
// Here, we collect the properties
const out = {};
// map the input array, splitting each line at |
input.map(i => i.split('|'))
.filter(a => a.length > 0) // lets not entertain empty lines in input
.forEach(a => { // process each array of property names
// start at outermost level
let p = out;
// iterate properties
for(const v of a){
// create a property if it is not already there
if(!p.hasOwnProperty(v)){
p[v] = {};
}
// move to the nested level
p = p[v];
}
});
// lets see what we have created
console.log(out);
A number of solutions have been suggested already, but I'm surprised none involves reduce() - which would seem the more idiomatic solution to me.
var array = [
"clothes|tshirt|tshirt-for-kids",
"clothes|coat|raincoat",
"clothes|coat|leather-coat",
"clothes|tshirt|tshirt-for-men",
"clothes|tshirt|tshirt-for-men|luxury-tshirt",
]
var object = array.reduce(function (object, element) {
var keys = element.split("|")
keys.reduce(function (nextNestedObject, key) {
if (!nextNestedObject[key]) nextNestedObject[key] = {}
return nextNestedObject[key]
}, object)
return object
}, {})
console.log(object)
One Liner With eval
Used eval to evaluate strings like the following:
'o["clothes"]??={}'
'o["clothes"]["tshirt"]??={}'
'o["clothes"]["tshirt"]["tshirt-for-kids"]??={}'
const
data = ["clothes|tshirt|tshirt-for-kids", "clothes|coat|raincoat", "clothes|coat|leather-coat", "clothes|tshirt|tshirt-for-men", "clothes|tshirt|tshirt-for-men|luxury-tshirt"],
arr = data.map((d) => d.split("|")),
res = arr.reduce((r, a) => (a.forEach((k, i) => eval(`r["${a.slice(0, i + 1).join('"]["')}"]??={}`)), r), {});
console.log(res)
One Liner Without eval
const
data = ["clothes|tshirt|tshirt-for-kids", "clothes|coat|raincoat", "clothes|coat|leather-coat","clothes|tshirt|tshirt-for-men", "clothes|tshirt|tshirt-for-men|luxury-tshirt"],
res = data.reduce((r, d) => (d.split("|").reduce((o, k) => (o[k] ??= {}, o[k]), r), r), {});
console.log(res)
I want to add or remove a dictionary on the array based on two cases.
For example,
Let us create a array of dictionary,
var Result=[{'a':1},{'b':2},{'c':3},{'d':4}];
Let us consider two cases,
Case-1:
An input dictionary that has both the same key and value which is in the Result variable.
input={'c':3}
then the result should be,
var Result=[{'a':1},{'b':2},{'d':4}];
Case-2:
An input dictionary that has the same key and different value(input1) and vice versa(input2) or both different key and value(input3) which the Result variable array have.
input1={'d':6}
input2={'x':3}
input3={'e':10}
then the result should be,
var Result=[{'a':1},{'b':2},{'c':3},{'d':4},{'d':6},{'x':3},{'e':10}];
Thanks in advance
You could find the index of the given key/value pair and remove this item of the array or push the object to the array.
This approach mutates the array.
function update(array, object) {
var [key, value] = Object.entries(object)[0],
index = array.findIndex(o => o[key] === value);
if (index === -1) {
array.push(object);
} else {
array.splice(index, 1);
}
}
var array = [{ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 }],
input1 = { c: 3 },
input2 = { d: 6 };
update(array, input1),
console.log(array);
update(array, input2);
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This question has been answered but i enjoyed the task.
Here is my working.
The logic is to combine both Arrays and if there is a key:value duplicate then ignore otherwise populate.
const INIT = [{'a':1},{'b':2},{'c':3},{'d':4}];
const input1 = {'c':3}
const input2 = {'d':6}
const input3 = {'x':3}
const input4 = {'e':10}
const INPUTS = [input1, input2, input3, input4]
const merge_and_de_dupe = (dictionary, overwrite) => {
const combined = [...dictionary, ...overwrite]
return combined.reduce((prev, curr, i, orig) => {
const [item_key, item_value] = Object.entries(curr)[0]
const all_duplicates = orig.filter(oI => item_key in oI && oI[item_key] === item_value)
return all_duplicates.length > 1 ? prev : [...prev, curr]
}, [])
}
const stripped = merge_and_de_dupe(INIT, INPUTS)
console.log(stripped)
Problem
I have a string of numerical values separated by commas, and I want to include them in an array, and also each pair of them to be an array nested inside of the main array to be my drawing vertices.
How do I solve this problem?
Input:
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
what I want them to be is:
Output:
var V_array = [[24,13],[47,20],[33,9],[68,18],[99,14],[150,33],[33,33],[34,15],[91,10]];
You could Split on every second comma in javascript and map the splitted pairs by converting the values to number.
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10",
result = vertices.match(/[^,]+,[^,]+/g).map(s => s.split(',').map(Number));
console.log(result);
You can use the function reduce which operates over the splitted-string and check for the mod of each index.
let str = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
let result = str.split(',').reduce((a, s, i) => {
a.curr.push(Number(s));
if ((i + 1) % 2 === 0) {
a.arr.push(a.curr);
a.curr = [];
}
return a;
}, {arr: [], curr: []}).arr;
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can split string into array and use reduce method. Take a look at the code below
const vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
const numbers = vertices.split(',').map(Number)
const res = numbers
.reduce((acc, number, index, srcArray) => {
if (index % 2) {
return acc
}
return [
...acc,
[ number, srcArray[index + 1] ],
]
}, [])
console.log(res)
My two cents :) [new version]
let
str = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10",
pair = [],
triplet = [];
JSON.parse(`[${str}]`).forEach((e,i)=>{pair.push( (i%2)?[pair.pop(),e]:e)})
console.log ( 'pair:', JSON.stringify(pair) )
// bonus => same idea for triplet :
JSON.parse(`[${str}]`).forEach((e,i)=>{
if ( (i%3)===2 ) triplet.push( [triplet.shift(),triplet.pop(),e] )
else if ( (i%3)===0 ) triplet.unshift(e)
else triplet.push(e)
})
console.log ( 'triplet:', JSON.stringify(triplet) )
You can use exec and JSON.parse
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
var array1;
var reg = /[^,]+,[^,]+/g
let op = []
while((array1 = reg.exec(vertices))!== null){
op.push(JSON.parse(`[${array1[0]}]`))
}
console.log(op)
Split on the , and use Array.reduce to group the pair into a new 2-D array:
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
const pair = vertices.split(",").reduce((acc, ele, idx, arr) => {
if(idx === 0 || idx%2 === 0) {acc.push([+ele, +arr[idx + 1]]);}
return acc;
}, []);
console.log(pair);
Same can be done using Array.map, if the index is odd skip the element and filter out the undefined elements:
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
const pair = vertices.split(",").map((ele, idx, arr) => (idx === 0 || idx%2 === 0) ? [+ele, +arr[idx + 1]] : undefined).filter(e => e);
console.log(pair);
My two cents :)
( thanks to Code Maniac for the idea of using JSON.parse )
let str = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
let result = JSON.parse(`[${str}]`).reduce((acc, cur, i) => {
if (i===1) return [[acc,cur]]
if (i%2) acc.push( [acc.pop(), cur] )
else acc.push( cur )
return acc
});
console.log ( result )
Here is my solution.
var vertices = "24,13,47,20,33,9,68,18,99,14,150,33,33,33,34,15,91,10";
vertices = vertices.split(",");
function convertToMultiArray (arr, length) {
var nArr = [];
while(arr.length > 0) {
nArr.push(arr.splice(0,length));
}
return nArr;
}
const res = convertToMultiArray(vertices, 2);
console.log('res', res);
var array1 = ["ddd","aaa","eee","aaa","fff","bbb","ggg","aaa","ccc","fff"]
i have to arrange it in a way that identical values has to be placed together
output array should be
["ddd","aaa","aaa","aaa","eee","fff","fff","bbb","ggg","ccc"]
how to write the logic for this one ??
You could iterate the array and check the position and if not the same as the actual element, splice the value to the earlier position.
var array = ["ddd","aaa","eee","aaa","fff","bbb","ggg","aaa","ccc","fff"],
i = 0, p;
while (i < array.length) {
p = array.indexOf(array[i]);
if (p !== i) {
array.splice(p, 0, array.splice(i, 1)[0]);
}
i++;
}
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Sort array using sort() method like this
var array1 = ["ddd","aaa","eee","aaa","fff","bbb","ggg","aaa","ccc","fff"];
console.log(array1.sort());
Well actually for you request .sort() might be an overkill. You can simply do this by;
function quasiSort(a){
var h = a.reduce((h,e) => h[e] ? (h[e].push(e), h)
: (h[e] = [e], h), {});
return Object.keys(h).reduce((r,k) => r.concat(h[k]),[]);
}
var array1 = ["ddd","aaa","eee","aaa","fff","bbb","ggg","aaa","ccc","fff"];
console.log(quasiSort(array1));
You can create one object to store values and index and then use that object to create new array.
var array1 = ["ddd","aaa","eee","aaa","fff","bbb","ggg","aaa","ccc","fff"],
obj = {}, i = 0
array1.forEach(function(e) {
if(!obj[e]) obj[e] = {index: i++, values: []}
obj[e].values.push(e)
})
var result = [].concat(...Object.keys(obj).reduce((r, e) => (r[obj[e].index] = obj[e].values, r), []))
console.log(result)