Stuck with building an object based on date from two separate arrays - javascript

So basically, I have an array of date between a range:
['2019-01-01, '2019-01-02', '2019-01-03'...'2019-01-30'];
And an array of objects containing data for the dates in the above range:
[{date: '2019-01-01', count: 2'}, {date: '2019-01-05', count: 4'}...{date: '2019-01-25', count: 3}]
Note, if there is no count at a particular date between those ranges in the first array, it does not appear in the second array at all. So, if there were 30 dates in the first array, there may only be 25 dates in the second array.
Ultimately, I would like to build an array of object in the form:
[
{ date: '2019-01-01',
count: 2
},
{
date: '2019-01-02',
count: 0
},
];
So, the array will contain an object for each date in the range (from first array), and will get the count (from the second array). If the date is not in the second array, then it will set the count as 0 in the array of objects.
I'm having a really hard time trying to figure out how to do this. I've tried various loops but am getting nowhere. Can anyone point me in the right direction?

Create a new array with same value number as range.
For each value of range, check in counts if there is already an existing count.
If there's one, return it. If there's none, return a new "0 count".
Code version:
const range = [
'2019-01-01',
'2019-01-02',
'2019-01-03',
'2019-01-04',
'2019-01-05',
'2019-01-06',
'2019-01-07',
];
const counts = [
{date: '2019-01-01', count: 2},
{date: '2019-01-05', count: 4},
{date: '2019-01-07', count: 3},
];
const result = range.map(date =>
counts.find(element => element.date === date) || { date, count: 0 });
console.log(result);

Related

How to rest only one value of an object inside an array of Objects

I have an array of objects. All of the objects have these keys and values :
const arr=[ { name: 'beer', amount: 50, price: 50 }]
function changeValue(){
// here I would like to receive back an array with the same object keys and values except amount.
// arr.amount should be 0
}
<button onclick='changeValue()'> Reset Amount </button>
How can I get back the same exact array with same objects, except the amount should be 0 for each one? I think this can be possible be done with the spread operator.
You can use rest parameters.
const arr=[ { name: 'beer', amount: 100, price: 50 }, { name: 'test', amount: 50, price: 10 }];
const res = arr.map(({amount, ...rest})=>({...rest, amount: 0}));
console.log(res);
You need to map the original array
function changeValue(something){
return arr.map( it => ({
...it,
amount: something
}))
}
You may also want to filter the it based on some criteria

Sort an array of date ranges into groups where each group has no overlapping ranges (Javascript)

I have an Array of objects & each object has a 'start' date & an 'end' date.
sortedDateRanges = [
{
id: 1,
start: "2018-01-01",
end: "2018-01-05",
name: "First item"
},
{
id: 2,
start: "2018-01-02",
end: "2018-01-08",
name: "Second item"
},
{
id: 3,
start: "2018-01-06",
end: "2018-01-13",
name: "Third item"
},
{
id: 4,
start: "2018-01-14",
end: "2018-01-14",
name: "Fourth item"
},
{
id: 5,
start: "2018-02-01",
end: "2018-02-15",
name: "Fifth item"
},
]
I need to sort these objects into groups where each group has NO overlapping date ranges. There are definitely multiple valid outputs. [[{id: 1},{id: 3},{id: 4}], [{id: 2},{id: 5}]] or [[{id: 1}, {id: 3}, {id: 5}], [{id: 2}, {id: 4}]] etc.
My current solution is just comparing each range to the previous range which doesn't produce an incorrect solution...it's just not a comprehensive solution like I am looking for. My current solution returns [[{id: 1}],[{id: 2}],[{id: 3}, {id: 4}, {id: 5}]]
export const groupUnoverlappedItems = sortedDateRanges => {
let groups = [];
let rangeIds = [];
sortedDateRanges.map((current, idx, arr) => {
if (idx === 0) {
groups.push([current]);
rangeIds.push(current.id);
// return result;
} else {
let previous = arr[idx -1];
// check for overlap
let previousEnd = (new Date(previous.end)).getTime();
let currentStart = (new Date(current.start)).getTime();
let overlap = (previousEnd >= currentStart);
if (overlap) {
// if overlap, push new group
groups.push([current]);
rangeIds.push(current.id);
} else if (rangeIds.indexOf(current.id) === -1) {
groups[groups.length -1].push(current);
rangeIds.push(current.id);
}
}
});
return groups;
};
I don't understand if you have a rule to define the groups, or they must be formed dinamically.
Anyway, why don't you get the object with the earliest start date, and use it to create the first object, in the first group.
You have a starting point, then you can find the object with the nearest start date, that doesn't overlap your first object end date. If you proceed sequentially, once you find a date that overlaps, you can be almost safe that is the good one to form the next group.
Once you don't find any other candidates for the first group, then you can check if another group exist (and has at least an object in it), then repeat the process, until all objects are allocated.
May I suggest to use a library, like date-fns, that helps you with useful methods to manipulate dates, and also define date intervals. Javascript has basic support for dates, using a library can save you a lot of time ;)

Cartesian product (all combinations) in array of multi-dimentonal objects with flexible length

There are several questions with answers on StackOverflow which shows how to find Cartesian product for various simple arrays. And a wonderful article on RosettaCode. But I can't find any solution for my problem.
I have an array of object with items, let's call it items:
let items = [{
id: 1
quantity: 2
field: "other_field"
},
{
id: 2
quantity: 3
field: "other_field"
}]
Every item in this array have a pricing/crafting method and we could receive it by request.
let pricing = getPricing(id) //item id
/*
Which will return to us:
*/
pricing = [
{pricing_id: 1, reagent_items: [/*array of objects, fields exactly items*/]},
{pricing_id: 2, reagent_items: [/*array of objects, fields exactly items*/]}
]
CARTESIAN PRODUCT PROBLEM:
As you may already understand, according to the answer's title, I want to receive all possible combinations of items AND reagent_items from pricing methods.
For example, if we have two items and all every item (of this 2) have just one pricing method, there will be 4 different combinations:
2 default items from items
first default item from items (item[0]) and all all reagent_items from getPricing for item[1]
second default item from items (item[1]) and all all reagent_items from getPricing for item[0]
both reagent_items from getPricing for both default items
I literally can't push reagent items to items (or remove item from items) array, because items can be the same (include each other) Instead of it, I am using my own Array.prototype.method for adding/removal items from items array. It does just the same as push/slice but in more elegant way, manipulating with id and quantity fields.
The actual problem lies in the field of arrays.length and for ... loop.
When we evaluate default Cartesian product we know before the array.length and it's elements.
But in my case I should getPricing every items, then receive array of methods..
Schema:
It's like:
Default: I_1 I_2 ... N
/ \ / \ / \
Get Pricing: [I_A, I_B][I_B, I_C] [IN_J, IN_K],
[IN_Y, IN_X, IN_Z],
So it's not about finding: Cartesian([I_A, I_B],[I_B, I_C]) but something like:
I_1 + I_2
I_1 + (I_B, I_C)
(I_A, I_B) + I_2
(I_A, I_B) + (I_B, I_C)
...
So default item includes each others and their reagent_items and it's simple to find all combinations of two items, but when it's become 3+..
My current pseudo code for now:
/* inside async*/
...
let ArrayOfPricing = [] //length 2, where each Array represent Array of `pricing` for each item
Promise.all(items.map(async item => {
const itemPricing = await getPricing(item.id);
ArrayOfPricing.push(itemPricing );
})
/**And what's next? **/
for (let item of items) {
}
So I can't understand what should I do next, at this stage.
Should I loop/iterate every item? But if so, even if I iterate every item one-by-one and change/remove it and add it's reagent_items (for every pricing) I still don't change the next item/element in array of items and it's length more then just 2, then I won't receive all the combinations, it will be like:
for items
↓
item[1] → for pricing
→ for reagent_items
↓
replace item[1] for all reagent_item
item[2] /** they are still there, but I need iterate over it's pricing , too **/
item[3]
or I could calculate all possible combinations by looking for items length and all pricing length and then form and empty new array with fixed length and push to all the combinations. But if I iterate over it for push with for loop... I should combine items and it will be for loop, inside for loop, inside for .. loop..
So to be honest I am out of ideas. I don't ask to write full working code instead of me, but to point me the way out of this loop. How to get every combination for every item and "baby-items" inside of it? How many cycles should I use then? I'll be grateful for any useful idea/pseudocode/post link which will help me to deal with this case. I'm also here and will check all the comments and answers below.
UPD a simple version of «from what I get, to what I want»
from this:
[
{
field: "original, can be cloned for every combination",
items:
[
{id: 1, quantity: 2},
{id: 2, quantity: 3}
]
}
]
to:
[
{
field: "original",
items:
[
{id: 1, quantity: 2},
{id: 2, quantity: 3}
]
},
{
field: "combination1",
items:
[
{id: 11, quantity: 1}, //from getPricing(item[0])
{id: 12, quantity: 1}, //from getPricing(item[0])
{id: 2, quantity: 3}
]
},
{
field: "combination2",
items:
[
{id: 1, quantity: 2},
{id: 22, quantity: 3} //from getPricing(item[1])
{id: 23, quantity: 3} //from getPricing(item[1])
]
},
{
field: "combination3",
items:
[
{id: 11, quantity: 1}, //from getPricing(item[0])
{id: 12, quantity: 1}, //from getPricing(item[0])
{id: 22, quantity: 3} //from getPricing(item[1])
{id: 23, quantity: 3} //from getPricing(item[
]
}
//can be any length according to getPricing of every item, and I modify original array, but we could create a new one.
]
As I promised, I have found a solution of my problem and I'd like to share it with StackOverflow Community.
Pseudo-code:
let array = [
{
field: "original, can be cloned for every combination",
items:
[
{id: 1, quantity: 2},
{id: 2, quantity: 3}
]
}
]
for (let element of array) {
let MethodsCombinations = [];
for await (let forCombinations of element.items.map((item, i) => {
return getMethod(item.id) //get Method for each item)
})) {
MethodsCombinations.push(forCombinations)
}
/* Cartesian product */
let vanilla_CartesianProduct = MethodsCombinations.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
/* Return array of arrays, with objects inside like default array */
/**
* Other logic with two for loops and merging all the combinations and quantities
* with (my own) modified Array.prototype.addItemToArray
*/
}
I am very grateful to this Nina Scholz's answer and her awesome StackOverflow profile with all answers about combinations/permutations and for providing a support.

javascript - pushing new property to objects that are in an array

I got an array person containing many objects that look like this:
const person = [
{ first: 'firstName', last: 'lastName', year: 1439, passed: 1495 },
...
]
I have counted how many years the person lived:
const oldest = person.map(x => x.passed - x.year);
Got new array with the years for every person.
Now I would like to push this calculated year as a new property age to each person object in this array.
Can you help me out?
You could add a new property
person.forEach(p => p.lifetime = p.passed - p.year);
Or map a new array of objects
persons = person.map(p => ({ ...p, lifetime: p.passed - p.year });
You can set the property directly by assigning value To it like this
Person[0].age = oldest[0]:
You can loop like this.
You can use array.forEach, which will iterate through the same array and you can create a new property to the same array.
If you want get a new array you can use array.map, which will create a new array.
I hope this will solve the issue.
const person = [
{ first: 'firstName', last: 'lastName', year: 1439, passed: 1489 },
{ first: 'secondName', last: 'lastName', year: 1499, passed: 1590 },
{ first: 'thirdName', last: 'lastName', year: 1539, passed: 1570 },
{ first: 'fourthName', last: 'lastName', year: 1993, passed: 2018 },
]
person.forEach(obj => obj["age"] = obj.passed - obj.year)
console.log("same array with added age property", person)
Since both arrays person and oldest have the same length, you can just iterate over either, construct new objects with age properties from the elements of both arrays at the same index and push them to a result array.
const person = [
{ first: 'firstName', last: 'lastName', year: 1439, passed: 1495 }
];
const oldest = person.map(x => x.passed - x.year);
const result = [];
person.forEach(({first, last, year, passed}, i) => result.push({first, last, year, passed, age: oldest[i]}));
console.log(result);
Given a zip function (which unfortunately is not yet standard JavaScript), you could also shorten this to:
zip(person, oldest).map(([{first last, year, passed}, age]) => ({first, last, year, passed, age}));

How do you create Object of Arrays in Javascript

I spent more time on this than I would like to admit. I have trouble constructing an object filled with an array.
I would like my data to look like this:
items={
{
'2012-05-22': [{text: 'item 1 - any js object'}],
'2012-05-23': [{text: 'item 2 - any js object'}],
'2012-05-24': [],
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
}
}
I am making a database call and the data I receive looks like this:
Object {start: "08:00:00", end: "09:00:00", full_name: "Tomomi", date: "2017-06-08", Barber_id: "1"…}
The data I am interested in is the full_name value and the date value.
This is what I have attempted:
let newItems = {};
axios.post(endpoint, {lookup: day.dateString}).then((customerData) => {
customerData.data.forEach((val,key)=>{
newItems = {[val.date]:[]};
newItems[val.date].push({name:val.full_name});
console.log(newItems);
})
}
It looks like this:
Object {2017-06-08: Array(1)}
2017-06-08
:
Array(1)
This is very close, but the problem is that my code is overwriting my data.
I am trying to create this dynamically:
'2012-05-25': [{text: 'item 3 - any js object'},{text: 'any js object'}],
So that each date can have many users. Hopefully, this makes sense.
Thanks for any help.
The function expression you pass to forEach has this as the first line:
newItems = {[val.date]:[]};
This resets the newItems object to an object with one date:name pair. You really want something more like:
newItems[val.date]?newItems[val.date].push({name:val.full_name}):newItems[val.date]=[];
var byDate = {}; // Object to store received data by-date
function addIntoByDate( obj ) {
byDate[obj.date] = byDate[obj.date] || [];
byDate[obj.date].push( obj );
}
// Simulate adding server data one by one
addIntoByDate( {date: "2017-06-08", full_name: "Cat", text:"Foo!!"} ); // < SAME DATE
addIntoByDate( {date: "2016-05-23", full_name: "Dog", text:"Bar"} );
addIntoByDate( {date: "2017-06-08", full_name: "Bug", text:"Baz..."} ); // < SAME DATE
// test
console.dir(byDate);
You can use object destructuring, computed property and Object.assign()
const newItems = {};
const data = [
{
start: "08:00:00"
, end: "09:00:00"
, full_name: "Tomomi"
, date: "2017-06-08"
, Barber_id: "1"
}
];
data.forEach(({date, full_name}) =>
Object.assign(newItems, {[date]: [{/* text: */ full_name}]}));
console.log(newItems);

Categories

Resources