Find minimum level in group and combine - javascript

In my application similar levels are grouped into an array, I need to fetch the minimum level in that group and replace with that minimum level in all the object. I couldn't get the desired result.
Input
let results = [ [{LEVEL:2,NAME:"ADAMS"},{LEVEL:3,NAME:"JAMES"}],
[{LEVEL:4,NAME:"SHYAM"}],
[{LEVEL:6,NAME:"JIM"},{LEVEL:7,NAME:"ARUN"}]
]
Output
output = [{LEVEL:2,NAME:"ADAMS"},
{LEVEL:2,NAME:"JAMES"},
{LEVEL:4,NAME:"SHYAM"} ,
{LEVEL:6,NAME:"JIM"},
{LEVEL:6,NAME:"ARUN"}
]
Code
result = results.reduce((r, a) => {
a.forEach(({LEVEL,NAME}) => {
var min = r.find(q => q.LEVEL > LEVEL);
if (!min) r.push({LEVEL,NAME});
});
return r;
}, []);
console.log(result)

Iterate with Array.flatMap(), and map each sub array items into the minimum LEVEL value.
You can use Array.map() to get an arrays of LEVEL, and then spread them in Math.min() to get the minimum value (see the getMinLevel() function).
const results = [[{LEVEL:2,NAME:"ADAMS"},{LEVEL:3,NAME:"JAMES"}],[{LEVEL:4,NAME:"SHYAM"}],[{LEVEL:6,NAME:"JIM"},{LEVEL:7,NAME:"ARUN"}]]
const getMinLevel = arr => Math.min(...arr.map(o => o.LEVEL))
const result = results.flatMap(arr => {
const LEVEL = getMinLevel(arr)
return arr.map(o => ({
...o,
LEVEL
}))
})
console.log(result)

For each group, you're going to have to loop through twice. Once to find the min LEVEL, and then again to apply that min. I've used the forEach function here to iterate through these arrays, and I've used a bit of shorthand as well. (group[0] || {LEVEL: 0}) checks if 0 is a valid index of group, and , if not, just uses a default object with a LEVEL of 0 to avoid errors. min > result.LEVEL ? result.LEVEL : min; checks if min is greater than result.LEVEL. If so, it yields result.LEVEL. Otherwise, it yields the current min.
let results = [
[{LEVEL: 2, NAME: "ADAMS"}, {LEVEL: 3, NAME: "JAMES"}],
[{LEVEL: 4, NAME: "SHYAM"}],
[{LEVEL: 6, NAME: "JIM"}, {LEVEL: 7, NAME: "ARUN"}]
];
results.forEach((group) => {
var min = (group[0] || {LEVEL: 0}).LEVEL;
group.forEach((result) => {min = min > result.LEVEL ? result.LEVEL : min;});
group.forEach((result) => {result.LEVEL = min;});
});
console.log(results);

If you still want to do with reduce and forEach combination then I guess you can do as follows:
const names = [
[ {LEVEL:2,NAME:"ADAMS"}, {LEVEL:3,NAME:"JAMES"} ],
[ {LEVEL:4,NAME:"SHYAM"} ],
[ {LEVEL:6,NAME:"JIM"}, {LEVEL:7,NAME:"ARUN"} ],
];
const result = names.reduce((accumulator, elem) => {
elem.forEach(e => {
const smallestNumber = Math.min.apply( Math, elem.map(a => a.LEVEL) );
accumulator.push({LEVEL: smallestNumber, NAME: e.NAME});
});
return accumulator;
}, []);
console.log(result);
I hope this helps!

Related

Count array of strings with reduce

I am trying to count how many identical values there are in an array of strings using reduce but this.
const arrayOfStrings = ["63955a83c1a9a4d5365b686c", "63955e3e478e25a859a6e7bb", "63955e3e478e25a859a6e7bb"]
const result = arrayOfStrings.reduce((prev, curr) => {
prev[curr] = prev[curr] || [{
id: curr,
amount: 0
}];
prev[curr][curr.amount] += 1
return prev;
}, [])
I'm currently getting a strange array, but it's not even close to what I want, I'm expecting something like this:
[
{
id: "63955a83c1a9a4d5365b686c",
amount: 1
},
{
id: "63955e3e478e25a859a6e7bb",
amount: 2
}
]
You need to initialise your reduce with an object rather than an array.
Update the amount by assigning the value to acc[c].amount.
Extract the values (the nested objects) with Object.values.
const arr = ["63955a83c1a9a4d5365b686c", "63955e3e478e25a859a6e7bb", "63955e3e478e25a859a6e7bb"];
const out = arr.reduce((prev, curr) => {
prev[curr] ??= { id: curr, amount: 0 };
prev[curr].amount += 1;
return prev;
}, {});
console.log(Object.values(out));
You can use find inside reduce to search whether the value is already present in the array and if yes, then update the amount value, otherwise initialize a new object and push it in the array.
const arrayOfStrings = ["63955a83c1a9a4d5365b686c", "63955e3e478e25a859a6e7bb", "63955e3e478e25a859a6e7bb"]
const result = arrayOfStrings.reduce((prev, curr) => {
let o = prev.find((obj) => obj.id === curr)
o ? o.amount++ : prev.push({ id: curr, amount: 1 })
return prev;
}, [])
console.log(result)

new Array Conditional values

I need to create a new array as you can see it has a key value that specifies the latitude and longitude.
I want the key values ​​that are equal to be set as 1 only but according to who has the highest count
[
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
]
let result = count.filter((e) => e && e.count && e.key == e.key);
let datas = result;
Is this what you're looking for?
const result = arr.reduce((acc, cur) => {
const matchIndex = acc.findIndex(saved =>
saved.latitud === cur.latitud
&& saved.longitud === cur.longitud
);
if (matchIndex !== -1) {
if (cur.count > acc[matchIndex].count) {
acc.splice(matchIndex, 1, cur);
}
return acc;
}
return [...acc, cur];
}, []);
It looks like the array contains objects that differ mostly by their count props but have several other duplicate props. I think I understand the OP to want to remove these almost-duplicates retaining the one with the highest count.
One way to do this is to sort the array to be descending by count, walk through them, pushing onto a result only those that aren't already in the result.
The only thing not super clear in the OP is what constitutes sameness besides the count field. Here, we guess that the coment_calification key being the same means the objects are to be treated as duplicate.
const objects = [
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
];
objects.sort((a,b) => b.count-a.count) // sort descending
const result = [];
for (let object of objects) {
// supposing matching coment_calification props means a match
let alreadyInResult = result.find(r => r.coment_calification === object.coment_calification)
if (!alreadyInResult) result.push(object);
}
console.log(result)

Loop through array for each value from another array

How can I loop through this array:
const counts = [
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk",
];
taking each value from this array?
const uniqueDomains = [
'google.com',
'com',
'mail.yahoo.com',
'yahoo.com',
'mobile.sports.yahoo.com',
'sports.yahoo.com',
'stackoverflow.com',
'overflow.com',
'com.com',
'en.wikipedia.org',
'wikipedia.org',
'org',
'm.wikipedia.org',
'mobile.sports',
'sports',
'google.co.uk',
'co.uk',
'uk'
]
I need to find out if string from counts array includes string from uniqueDomains array.
Then push it to the empty object as a key value pairs, where value
is going to be the number in the beginning of the each string from counts array.
I tried this code but it give me wrong result in my object's values(since I am looping twice)
I need kind of avoid looping twice, but I am not sure how.
Example com is mentioned 8 time in counts array, which means result should be this {com: 1345}
Here is my code:
const finalObject = {}
uniqueDomains.forEach((dom) => {
counts.forEach((cnt) => {
if (cnt.includes(dom)) {
const num = parseInt(cnt);
sumArr.push(num);
const res = sumArr.reduce((acc, cur) => {
return acc + cur;
});
finalObject[dom] = res;
}
});
});
Theres not really any avoiding looping twice (at least), but you can certainly make your code a bit easieer by first turning the count array into an array of val & domain separately.
const countIdx = counts.map(x => {
const [val,domain] = x.split(",");
return {val:parseInt(val,10), domain}
});
Then its just a case of looping the uniqueDomain array and finding all the domaion which match and summing up the val
const result = uniqueDomains.reduce( (res, d) => {
const count = countIdx.filter(x => x.domain.includes(d)).reduce( (acc,x) => acc + x.val,0);
return {...res, [d]:count}
},{});
Live example follows:
const counts = [
"900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"20,overflow.com",
"5,com.com",
"2,en.wikipedia.org",
"1,m.wikipedia.org",
"1,mobile.sports",
"1,google.co.uk",
];
const uniqueDomains = [
'google.com',
'com',
'mail.yahoo.com',
'yahoo.com',
'mobile.sports.yahoo.com',
'sports.yahoo.com',
'stackoverflow.com',
'overflow.com',
'com.com',
'en.wikipedia.org',
'wikipedia.org',
'org',
'm.wikipedia.org',
'mobile.sports',
'sports',
'google.co.uk',
'co.uk',
'uk'
]
const countIdx = counts.map(x => {
const [val,domain] = x.split(",");
return {val:parseInt(val,10), domain}
});
const result = uniqueDomains.reduce( (res, d) => {
const count = countIdx.filter(x => x.domain.includes(d)).reduce( (acc,x) => acc + x.val,0);
return {...res, [d]:count}
},{});
console.log(result);
Maybe try something like:
let finalObject = {}
uniqueDomains.forEach((dom) => {
finalObject[dom] = 0;
counts.forEach((cnt) => {
if (cnt.includes(dom)) {
finalObject[dom] += parseInt(cnt);
}
});
});

Filter an array of objects, by keys in filter object

i'm new here, i have problem that i can not solve.
I have 2 different arrays:
The first array - contains ratings of users with their ID name
[
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
]
The second set - contains the ratings, which I want to return to each user.
If there is a rating that is not in the second set, I will not return it
In the second set, values do not matter, only keys
[
"_assembler",
"_css",
"_python",
"_php"
]
I want to return to the first set, the handle, and all the rankings that exist in the second set.
[
{"handle":"frontend1", "_python":"3" },
{"handle":"frontend3", "_php":"4", "_python":"5" },
{"handle":"frontend4"}
]
this is what i try to do.
keys = [
"_assembler",
"_css",
"_python",
"_php"
]
source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
result = [];
tmp = {};
source.forEach((item) => {
Object.keys(item).map(({key,value}) =>
{
if(key == "handle")
{
tmp[key]=value;
}
if(keys.includes(key))
{
tmp[key]=value;
}
})
result.push(...tmp);
tmp = {};
});
You can do this with a map utilizing a couple of other array methods such as filter, and Object methods.
const keys = [
"_assembler",
"_css",
"_python",
"_php"
]
const source = [
{"handle":"frontend1", "_redis":"3", "_nodejs":"5", "_mysql":"2", "_python":"3", "_mongo":"4"},
{"handle":"frontend3", "_php":"4", "_mysql":"4", "_oracle":"4", "_ruby":"3", "_mongo":"5", "_python":"5"},
{"handle":"frontend4", "_java":"5", "_ruby":"5", "_mysql":"5", "_mongo":"5"}
];
const result = source.map( s => ({
handle: s.handle,
...Object.fromEntries(Object.entries(s).filter(x => x[0] != "handle" && keys.includes(x[0])))
}));
console.log(result);

Get all Indexes of Objects in Array - from Array in Object

i´m struggling with a Array in a Object stored in a Array with Objects from which I want return all Indicies.
Function to generate Object looks like this:
const addArray = function(a, b) {
const object = {
name: a,
rooms: b
};
testArray.push(object);
};
What I want to achieve is to cycle through the "testArray" and return every Index from the Object where the Array Rooms contains "Office" for example.
I´ve already tried to use a function like this but I don´t seem to be able to get the right Syntax for the Array in the Object:
function getAllIndexes(arr, val) {
var indexes = [], i = -1;
while ((i = arr.rooms.indexOf(val, i+1)) != -1){
indexes.push(i);
}
return indexes;
};
Thanks in advance!
Edit:
Additional Informations to Data:
A Object with data filled would look like this:
const device = {
name: "TV",
rooms: ["Living Room", "Bedroom"]
};
After generating Objects like this I push them to an array witch only contains this objects (see function addArray)
You can use Array.flatMap() to map each value of the array at matches val to it's index, and the rest to empty array, which will be removed by the flatMap:
const getAllIndexes =(arr, val) => arr.flatMap((v, i) => v === val ? i : [])
const arr = [1, 2, 3, 1, 2, 1, 1, 2]
const result = getAllIndexes(arr, 1)
console.log(result)
Using your array of objects, you'll need to compare a value, or check if an object meets some condition. It's better in this case to replace val with a predicate function:
const getAllIndexes =(arr, pred) => arr.flatMap((v, i) => pred(v) ? i : [])
const arr = [{ rooms: [1, 2, 3] }, { rooms: [2, 1, 1] }, { rooms: [3, 2, 2] }, { rooms: [1, 2, 1] }]
const result = getAllIndexes(arr, o => o.rooms.includes(1))
console.log(result)
Try using Array.prototype.map and Array.prototype.filter
function getAllIndexes(arr, val) {
return arr.map(i=> {
let room = i.rooms;
return room.indexOf(val);
}).filter(a=>{
a != -1;
});
};
You could destructure rooms from the device and get the index, if the wanted value is found.
const
room = 'Office',
indices = array.flatMap(({ rooms }, i) => rooms.includes(room) ? i : []);
The above code features a former solution from me with hacking Array#flatMap.

Categories