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);
}
});
});
Related
I have an Array of objects and one object
const filterArray = [{bestTimeToVisit: 'Before 10am'}, {bestDayToVisit: Monday}]
This values are setting in a reducer and the payload will be like
{bestTimeToVisit: 'After 10am'}
or
{bestDayToVisit: Tuesday}.
So what I need is when I get a payload {bestTimeToVisit: 'After 10am'} and if bestTimeToVisit not in filterList array, then add this value to the filterList array.
And if bestTimeToVisit already in the array with different value, then replace the value of that object with same key
if(filterArray.hasOwnProperty("bestTimeToVisit")) {
filterArray["bestTimeToVisit"] = payload["bestTimeToVisit"];
} else {
filterArray.push({"bestTimeToVisit": payload["bestTimeToVisit"]});
}
I convert the object array into a regular object and then back into an object array. makes things less complicated. I'm making the assumption each object coming back only has one key/value and that order doesnt matter.
const objectArraytoObject = (arr) =>
arr.reduce((acc, item) => {
const key = [Object.keys(item)[0]];
return { ...acc, [key]: item[key] };
}, {});
const newValues = [{ someKey: 'something' }, { bestDayToVisit: 'Tuesday' }];
const filterArray = [
{ bestTimeToVisit: 'Before 10am' },
{ bestDayToVisit: 'Monday' },
];
const newValuesObj = objectArraytoObject(newValues);
const filterObj = objectArraytoObject(filterArray);
const combined = { ...filterObj, ...newValuesObj };
const combinedToArray = Object.keys(combined).map((key) => ({
[key]: combined[key],
}));
console.log(combinedToArray);
Need to iterate over the array and find objects that satisfy for modification or addition if none are found.
function checkReduced(filterrray,valueToCheck="After 10am"){
let isNotFound =true;
for(let timeItem of filterrray) {
if(timeItem.bestTimeToVisit && timeItem.bestTimeToVisit !== valueToCheck) {
timeItem.bestTimeToVisit=valueToCheck;
isNotFound=false;
break;
}
}
if(isNotFound){filterrray.push({bestTimeToVisit:valueToCheck})}
}
const filterArray = [{bestDayToVisit: "Monday"}];
checkReduced(filterArray,"After 9am");//calling the function
const updateOrAdd = (arr, newItem) => {
// get the new item key
const newItemKey = Object.keys(newItem)[0];
// get the object have the same key
const find = arr.find(item => Object.keys(item).includes(newItemKey));
if(find) { // the find object is a reference type
find[newItemKey] = newItem[newItemKey]; // update the value
} else {
arr.push(newItem); // push new item if there is no object have the same key
}
return arr;
}
// tests
updateOrAdd([{ a: 1 }], { b: 2 }) // => [{ a: 1 }, { b: 2 }]
updateOrAdd([{ a: 1 }], { a: 2 }) // => [{ a: 2 }]
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!
I'm working on an existing project that takes query parameters in an oddly formatted string dot notation. But they must be converted into objects before processing. This is currently being performed with conditionals on specific keys by name.
How can this be performed dynamically? Below you will find an example of the input and desired output.
Input:
{
date.gte: '2019-01-01',
date.lt: '2020-01-01'
}
Output:
{
date: {
gte: '2019-01-01',
lt: '2020-01-01'
}
}
You could use reduce and split methods to split each key into array and build nested structure based on that array.
const data = {
'date.gte': '2019-01-01',
'date.lt': '2020-01-01'
}
const result = Object.entries(data).reduce((r, [k, v]) => {
k.split('.').reduce((a, e, i, ar) => {
return a[e] || (a[e] = ar[i + 1] ? {} : v)
}, r)
return r;
}, {})
console.log(result)
By you saying "oddly formatted string dot notation" I assume you mean "date.gte" & "date.lt"
const input = {
"date.gte": "2019-01-01",
"date.lt": "2020-01-01"
};
const res = Object.keys(input).reduce(
(result, current) => {
const [, operator] = current.split(".");
result.date[operator] = input[current];
return result;
},
{ date: {} }
);
console.log(res);
Here's an improvement on Dan's answer that doesn't rely on knowing the key-value pairs in the original object. As much as Nenad's answer blows this out of the water, I worked for too long on this to not post it :)
const formatter = (weirdObject, s = '.') => Object.keys(weirdObject).reduce((acc, cur) => {
const [parent, child] = cur.split(s);
if (!acc[parent]) acc[parent] = {};
acc[parent][child] = weirdObject[cur];
return acc;
}, {});
// -- Demonstration:
const input1 = {
"date.gte": "2019-01-01",
"date.lt": "2020-01-01"
};
const input2 = {
"person:name": "Matt",
"person:age": 19
};
const res1 = formatter(input1);
const res2 = formatter(input2, ':');
console.log(res1);
console.log(res2);
I want to make filter by date with this object of array
const mapDateRange = () => {for (let elem in catchData) {
let x = {startDate:catchData[elem][0],finishDate:catchData[elem][1]};
return x;
}};
but its only catch one object of array
this is latest data has processing
const data = {
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
};
this is what i expected
const data = [
{
startDate:"01-08-2019", finisDate:"08-08-2019"
},
{
startDate:"08-08-2019", finisDate:"15-08-2019"
},
{
startDate:"15-08-2019", finisDate:"22-08-2019"
},
{
startDate:"22-08-2019", finisDate:"29-08-2019"
}
];
So there are a few problems in the code you wrote:
Your data started as an object ({}), but its built as an array, so I corrected that.
Your function mapDateRange uses catchData but it does not exist anywhere so I made the function except an argument, which will be the catchData.
Most important: You returned x which is only 1 item in the array of data. So I created an empty array and pushed x values to the array.
const data = [
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
];
const mapDateRange = (catchData) => {
let new_data = [];
for (let elem in catchData) {
let x = {
startDate: catchData[elem][0],
finishDate: catchData[elem][1]
};
new_data.push(x);
}
return new_data;
};
console.log(mapDateRange(data));
const data = [
["01-08-2019", "08-08-2019"],
["08-08-2019", "15-08-2019"],
["15-08-2019", "22-08-2019"],
["22-08-2019", "29-08-2019"]
];
const mapDataRange = (data) => {
const result = [];
data.forEach((item) => {
const x = { 'startDate': item[0], 'finishDate': item[1] };
result.push(x);
});
return result;
}
console.log(mapDatatRange(data));
In this way you will get your desire result by using map function
data = data.map((obj) => {
return {
startDate: obj[0],
finishDate: obj[1]
}
});
console.log(data)
try to do with .map and array destructuring with ES6 syntax
data.map(([ startDate, finishDate ]) => { startDate, finisDate })
I need to group by id and sum, but I need a new object for each result:
let data = [
{"id":"2018", "name":"test", "total":1200},
{"id":"2019", "name":"wath", "total":1500},
{"id":"2019", "name":"wath", "total":1800},
{"id":"2020", "name":"zooi", "total":1000},
]
I have this code that returns just one object with the result
let result = data.reduce(function (r, o) {
(r[o.id])?
r[o.id] += o.total:
r[o.id] = o.total;
return r;
});
But I need some like this:
[
{"id":"2018", "name":"test", "total":1200},
{"id":"2019", "name":"wath", "total":2300},
{"id":"2020", "name":"zooi", "total":1000},
]
How can I do it?
let data =[
{"id":"2018", "name":"test", "total":1200},
{"id":"2019", "name":"wath", "total":1500},
{"id":"2019", "name":"wath", "total":1800},
{"id":"2020", "name":"zooi", "total":1000},
];
let map = data.reduce((prev, next) =>{
if (next.id in prev) {
prev[next.id].total += next.total;
} else {
prev[next.id] = next;
}
return prev;
}, {});
let result = Object.keys(map).map(id => map[id]);
console.log(result);
You can try this:
const result = Object.values(data.reduce((r, o) => (r[o.id]
? (r[o.id].total += o.total)
: (r[o.id] = {...o}), r), {}));
Change your reduce to:
let result = data.reduce(function(acc, obj) { // for each obj in data
if(acc.map.hasOwnProperty(obj.id)) { // if the map contains an object for the current object's id
acc.map[obj.id].total += +obj.total; // then add the current object's total to it
} else { // otherwise
var newObj = Object.assign({}, obj); // create a new object (a copy of the current object)
acc.map[obj.id] = newObj; // add the new object to both the map
acc.data.push(newObj); // ... and the data array
}
return acc;
}, {data: [], map: {}}).data; // the accumulator should have an array for the data objects (which will be our result) and a map object which maps the ids to the objects in the data array. Once our reduce finishes its work, we assign the data array of the accumulator to result
Example:
let data =[ {"id":"2018", "name":"test", "total":1200}, {"id":"2019", "name":"wath", "total":1500}, {"id":"2019", "name":"wath", "total":1800}, {"id":"2020", "name":"zooi", "total":1000} ];
let result = data.reduce(function(acc, obj) {
if(acc.map.hasOwnProperty(obj.id)) {
acc.map[obj.id].total += +obj.total;
} else {
var newObj = Object.assign({}, obj);
acc.map[obj.id] = newObj;
acc.data.push(newObj);
}
return acc;
}, {data: [], map: {}}).data;
console.log(result);
import uniqBy from 'lodash/uniqBy'
export function transform (array) {
const newArray = []
const uniq = uniqBy(array, 'id')
uniq.forEach(item => {
const total = array
.filter(({id}) => item.id === id)
.reduce((sum, current) => sum + current.total, 0)
newArray.push({
...item,
total
})
})
return newArray
}