Time Converter: split content time with ads time - javascript

I'm sorry I have a trying to find & fix a math problem
Let's say I have 2 List or array
Content Array
0-50 = C1
50-100 = C2
AD Array
10-20 = A1
30-60 = A2
80-140 = A3
OutPut Should be Like this
0-10 = C1
10-20 = A1
20-30 = C1
30-60 = A2
60-80 = C2
80-100 = A3
Here ads are replacing actual content and splitting the content into a new array of items.
const content = [
{start: 0, end: 50, id: 'C1'},
{start: 50, end: 100, id: 'C2'},
]
const ad = [
{start:10, end: 20, id: 'A1' },
{start:30, end: 60, id: 'A2' },
{start:80, end: 140, id: 'A3' },
]
const newList = []
content.forEach(content => {
ad.forEach((ad, index) => {
//0 > 0 && 20 < 50
if(content.start < ad.start && content.end > ad.end){
newList.push({start: content.start, end: ad.start, id: content.id})
newList.push(ad)
}else{
console.log(decodeURIComponent(`${content.start} > ${ad.start} && ${content.end} < ${ad.end}`))
}
})
})
console.log('newList',newList)
Please Help

Actually, I don't know what I can say about the code, just try this approach:
const content = [{start: 0, end: 50, id: 'C1'},{start: 50, end: 100, id: 'C2'}];
const ad = [{start:10, end: 20, id: 'A1' },{start:30, end: 60, id: 'A2' },{start:80, end: 140, id: 'A3' }];
const cPoints = content.flatMap(e => [e.start, e.end]); // [0, 50, 50, 100]
const aPoints = ad.flatMap(e => [e.start, e.end]); // [10, 20, 30, 60, 80, 140]
const rangeMin = Math.min(...cPoints); // 0
const rangeMax = Math.max(...cPoints); // 100
const rangePoints = [...new Set([...aPoints, ...cPoints])] // [10, 20, 30, 60, 80, 140, 0, 50, 100]
.filter(point => (point >= rangeMin) && (point <= rangeMax)) // [10, 20, 30, 60, 80, 0, 50, 100]
.sort((a, b) => a - b); // [0, 10, 20, 30, 50, 60, 80, 100]
const getObjByPoint = (point, arr) =>
arr.find((e) => (e.start <= point) && (point <= e.end));
const getFirstId = (point) =>
(getObjByPoint(point, ad) || getObjByPoint(point, content)).id;
const result = rangePoints.reduce((acc, end, index, arr) => {
if (index === 0) return acc;
let start = arr[index - 1];
const middle = (start + end) / 2;
const id = getFirstId(middle);
if (acc.at(-1)?.id === id) {
start = acc.pop().start;
}
acc.push({ start, end, id });
return acc;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

This may be a "not so elegant" solution to achieve the desired objective.
Code Snippet
// manipulate timeline to find "gaps" and place "ads"
// recursive method controlled by "idx"
const splitTimeline = (arr, advArr, idx) => {
const res = [...arr]; // shallow-copy intermediate result array
const ad = advArr[idx]; // direct access to current iteration of "ad"
arr.forEach(
({ start, end, id }, rIdx) => { // de-structure and res-array-index
if ( // place "ad" in existing "gap"
start < ad.start &&
end >= ad.end &&
id === 'gap'
) {
res.splice(rIdx, 1, { start, end: ad.start, id: 'gap'});
res.splice(rIdx + 1, 0, {
start: ad.start, end: Math.min(end, ad.end), id: ad.id
});
if (end > ad.end) res.splice(rIdx + 2, 0, {
start: ad.end, end, id: 'gap'
});
} else if ( // handle edge-case (last "ad" exceeds timeline
idx === advArr.length - 1 && id === 'gap' &&
ad.start > start && ad.start < end
) {
res.splice(rIdx, 1, {
start: ad.start, end: end, id: ad.id
});
res.splice(rIdx, 0, {
start: start, end: ad.start, id: 'gap'
});
}
}
);
// recurse if all "ads" not yet processed
if (idx < advArr.length - 1) return splitTimeline(res, advArr, idx + 1);
else return res;
};
// method to fill "gaps" with "content" (c-array - content-array)
const addContent = (tl, carr) => ( // "tl" is current timeline
tl.map(({ start, end, id }) => { // iterate over "tl"
// if "ad", simply return it as-is
if (id !== 'gap') return {start, end, id};
// otherwise, find a matching "content" id for existing "gap"
return {start, end, id: carr.find(
ob => start >= ob.start && end <= ob.end
)?.id ?? "no content"} // optional chain "id" or return "no content"
})
);
// simple method to construct, update a timeline
// and place contents and ads within the timeline
const placeAds = (cn, ad) => {
const cBgn = Math.min(...cn.map(({ start }) => start));
const cEnd = Math.max(...cn.map(({ end }) => end));
const initialTimeline = [{
start: cBgn, end: cEnd, id: 'gap'
}];
return (
addContent( // method to add "content"
splitTimeline( // method to split timelines and place "ads" and "gaps"
initialTimeline,
ad, // the ad array
0 // initial ad array index set to 0 (for recursion)
),
cn // the content array
)
);
};
const content = [
{start: 0, end: 50, id: 'C1'},
{start: 50, end: 100, id: 'C2'},
];
const ad = [
{start:10, end: 20, id: 'A1' },
{start:30, end: 60, id: 'A2' },
{start:80, end: 140, id: 'A3' },
];
console.log(placeAds(content, ad));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Explanation
Inline comments describe the significant aspects of the solution

Related

How can I create a dynamic array based on another array in javascript/typescript?

I want to create an array to loop over one of the parameters of the first array (in this example, the desired parameter is the DT) and check whether we have data for different applications on those dates. If we have it, it will put its value (in the second array) and if we don't have it, it will put 0.
What I did was also with const pluck = (arr, key) => arr.map(i => i[key]);, I obtained the desired field dates (but they had duplicate values). To remove duplicate values I used dates = [...new Set(dates)]; and finally looped over the final values and wrote a series of codes, but I didn't get what I wanted (Expected Array in below).
first_array = [
{
DT: "2022-01-01",
APP: "Application 1",
SPEED: 1547,
},
{
DT: "2022-01-01",
APP: "Application 2",
SPEED: 685,
},
{
DT: "2022-01-02",
APP: "Application 1",
SPEED: 500,
},
{
DT: "2022-01-02",
APP: "Application 2",
SPEED: 300,
},
{
DT: "2022-01-02",
APP: "Application 3",
SPEED: 600,
},
{
DT: "2022-01-03",
APP: "Application 1",
SPEED: 1000,
},
]
Expected Array:
desire_array = [
{
Name: "Application1",
Values: [1547, 500, 1000],
ValuesWithDate: [{x: '2022-01-01', y: 1547}, {x: '2022-01-02', y: 500}, {x: '2022-01-03', y: 1000}],
},
{
Name: "Application2",
Values: [685, 300, 0],
ValuesWithDate: [{x: '2022-01-01', y: 685}, {x: '2022-01-02', y: 300}, {x: '2022-01-03', y: 0}],
},
{
Name: "Application3",
Values: [0, 600, 0],
ValuesWithDate: [{x: '2022-01-01', y: 0}, {x: '2022-01-02', y: 600}, {x: '2022-01-03', y: 0}],
},
]
The reason I need to do this is to create a series that I can use to display the chart with ApexCharts.
Real data can also be displayed from this api as JSON.
You can do:
const first = [{DT: '2022-01-01',APP: 'Application 1',SPEED: 1547,},{DT: '2022-01-01',APP: 'Application 2',SPEED: 685,},{DT: '2022-01-02',APP: 'Application 1',SPEED: 500,},{DT: '2022-01-02',APP: 'Application 2',SPEED: 300,},{DT: '2022-01-02',APP: 'Application 3',SPEED: 600,},{DT: '2022-01-03',APP: 'Application 1',SPEED: 1000,}]
const dates = [...new Set(first.map(({ DT }) => DT))]
const apps = [...new Set(first.map(({ APP }) => APP))]
const result = apps.reduce((acc, app) => {
const appData = Object.assign(
{},
{
Name: app.replace(/ /, ''),
Values: [],
ValuesWithDate: [],
}
)
dates.forEach((date) => {
const data = first.find(({ DT, APP }) => DT === date && APP === app)
appData.ValuesWithDate.push({ x: date, y: data ? data.SPEED : 0 })
appData.Values.push(data ? data.SPEED : 0)
})
acc.push(appData)
return acc
}, [])
console.log(result)
You can try with something like this :
const convertArray = (arr) => arr.reduce((prev, current) => {
const existingIndex = prev.findIndex((p) => p.Name === current.APP);
if (existingIndex > -1) {
const currentApp = prev[existingIndex];
currentApp.Values.push(current.SPEED);
currentApp.ValuesWithDate.push({x: current.DT, y: current.SPEED});
prev[existingIndex] = currentApp;
} else {
prev.push({Name: current.APP, Values: [current.SPEED], ValuesWithDate:[{x: current.DT, y: current.SPEED}]})
}
return prev;
}, []);
And use it like this :
const desire_array = convertArray(first_array)
const convert = (dates, data) => {
return Object.values(data.reduce((acc, curr) => {
if (!acc[curr.APP]) {
acc[curr.APP] = {
name: curr.APP,
valuesWithDate: []
};
}
acc[curr.APP].valuesWithDate.push({
x: curr.DT,
y: curr.SPEED
});
return acc;
}, {})).map((dataWithoutGaps) => {
const valuesWithDate = [...new Set(dates)].map(date => {
const el = dataWithoutGaps.valuesWithDate.find(e => e.x === date);
return {
x: date,
y: el ? el.y : 0
};
});
return {
ValuesWithDate: valuesWithDate,
Values: valuesWithDate.map(e => e.y),
Name: dataWithoutGaps.name
}
});
};
console.log(convert(first_array.map(e => e.DT), first_array));
Expected:
[{"ValuesWithDate":[{"x":"2022-01-01","y":1547},{"x":"2022-01-02","y":500},{"x":"2022-01-03","y":1000}],"Values":[1547,500,1000],"Name":"Application 1"},{"ValuesWithDate":[{"x":"2022-01-01","y":685},{"x":"2022-01-02","y":300},{"x":"2022-01-03","y":0}],"Values":[685,300,0],"Name":"Application 2"},{"ValuesWithDate":[{"x":"2022-01-01","y":0},{"x":"2022-01-02","y":600},{"x":"2022-01-03","y":0}],"Values":[0,600,0],"Name":"Application 3"}]
Your expected result can be achieved by this code.
let filtered_app = new Set();
const obj = [];
first_array.forEach(item=>{
filtered_app.add(item.APP);
});
filtered_app.forEach(app =>{
first_array.forEach(item =>{
if(item.APP == app){
const exists = obj.findIndex(elem => elem.Name == app);
if(exists != '-1'){
obj[exists].Values.push(item.SPEED);
obj[exists].ValuesWithDate.push({x: item.DT, y: item.SPEED});
}
else{
obj.push({Name: app, Values: [item.SPEED], ValuesWithDate: [{x: item.DT, y: item.SPEED}]});
}
}
});
});
console.log(obj);
Hope it helps.

Java Script Random Number Generator Issue

I have the code to generate a random number and it seemes to be cycling back and forth between 1 or 2.
const isDnaUnique = (_DnaList = [], _dna = []) => { let foundDna =
_DnaList.find((i) => i.join("") === _dna.join("")); return foundDna == undefined ? true : false; };
const createDna = (_races, _race) => { let randNum = [];
_races[_race].layers.forEach((layer) => {
let randElementNum = Math.floor(Math.random() * 100) + 1;
let num = 0;
layer.elements.forEach((element) => {
if (randElementNum >= 100 - element.weight) {
num = element.id;
}
});
randNum.push(num); }); return randNum; };
My issue is the random number generator keeps only returning to values instead of cycling through all of them.
{
name: "Eyes",
elements: [
{
id: 0,
name: "E1",
path: `${dir}/3-eyes/E1.png`,
weight: 25,
},
{
id: 1,
name: "E2",
path: `${dir}/3-eyes/E2.png`,
weight: 25,
},
{
id: 2,
name: "E3",
path: `${dir}/3-eyes/E3.png`,
weight: 25,
},
{
id: 3,
name: "E4",
path: `${dir}/3-eyes/E4.png`,
weight: 25,
},
],
position: { x: 0, y: 0 },
size: { width: width, height: height },
},
Your results are exactly what I would expect. Let's take a look.
Your randElementNum is going to be a number from 1 to 100. All four of your elements have weight of 25. You are running through the loop for all of the elements every time. So, if the number is less than 75 (100-25), then the if statement never fires, and num will be 0. If the number is greater than or equal to 75, then the if statement fires all four times, and you'll end up with element #3. There are no other possibilities.
The next big problem is that "forEach" is the wrong tool. I've shown you how to make it work below, but you really should be using an old-fashioned "for" loop, so you can break the loop once you find an answer.
I'm not sure what effect you were trying for, but this is certainly not what you intended. Based on the name weight, were you trying to have each element get picked 25% of the time? You can do that with something like this:
const createDna = () => {
let randElementNum = Math.floor(Math.random() * 100);
console.log( randElementNum );
let num = -1;
layer.elements.forEach((element) => {
if( num >= 0 )
return;
if (randElementNum < element.weight)
{
num = element.id;
return;
}
randElementNum -= element.weight;
});
return num;
};

Find pair of employees that have worked together the longest on common project

Kind of a duplicate but not at the same time because it's in python so I'm reposting it. The outputs are different as well for the same inputs.
Got a complicated assignment that I finally managed to solve but the algorithm I came up with is quite slow.
I'm pretty sure its around n^2 + n in worst case scenario.
It's supposed to go through a list of employees and return a list of employee pairs that have accumulated the most days worked together on common projectS. (the s is important)
Format for input:
EmployeeID, ProjectID, StartDate, EndDate(NULL === today)
Example input:
1,1,2019-7-4,2020-8-14
1,2,2019-12-25,2020-12-28
1,3,2018-10-12,NULL
1,4,2019-11-16,NULL
1,5,2020-1-5,2020-12-21
2,1,2018-10-3,NULL
2,2,2019-1-16,2020-3-24
2,3,2019-5-22,2019-12-26
2,4,2020-3-7,NULL
2,5,2018-1-24,2019-1-15
3,1,2019-3-21,2020-11-26
3,5,2019-9-28,2020-12-25
4,2,2018-10-22,NULL
4,3,2018-1-27,2020-8-28
5,3,2018-2-3,2020-10-14
5,5,2018-8-4,NULL
Format for output:
Employee#1, Employee#2, CommonProjectID, DaysWorked
Example output:
1,2,1,407
1,2,2,90
1,2,3,219
1,2,4,513
Here's my take on it but as I said it's quite slow and I was asked to try to optimize it. Been working on this for 5 hours now and can't come up with anything better.
export default function getHighestPair(empl) {
console.log(empl);
let pairs = {};
let daysTogether = {};
if (empl)
empl.forEach((el1) => {
/*
.slice() is used to exclude the current employee and employees before him
from the search which slightly reduces complexity. This is because
employee 5 + employee 13 is the same as employee 13 + employee 5
*/
empl.slice(empl.indexOf(el1) + 1, empl.length).forEach((el2) => {
// get start and end date of each of employee
if (el1[0] !== el2[0]) {
const startDate1 = new Date(el1[2]);
const endDate1 = el1[3] === "NULL" ? new Date() : new Date(el1[3]);
const startDate2 = new Date(el2[2]);
const endDate2 = el2[3] === "NULL" ? new Date() : new Date(el2[3]);
// check if they are in the same team (working on the same project)
if (el1[1] === el2[1]) {
if (startDate1 <= endDate2 && startDate2 <= endDate1) {
// calculate the start and end day that we need
const start = startDate1 <= startDate2 ? startDate2 : startDate1;
const end = endDate1 <= endDate2 ? endDate1 : endDate2;
if (end >= startDate2) {
// put them inside this formula and we get the time they have worked together in days
const diffTime = Math.abs(end - start);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
const x = `${el1[0]}${el2[0]}`;
if (!daysTogether[x]) Object.assign(daysTogether, { [x]: 0 });
daysTogether[x] = 1 * daysTogether[x] + diffDays;
if (!pairs[x]) Object.assign(pairs, { [x]: [] });
pairs[x] = [...pairs[x], [el1[0], el2[0], el1[1], diffDays]];
}
}
}
}
});
});
/*
gets the index of the pair that have worked together the longest toghether from
"daysTogether" which keeps count of the days for each project
*/
return pairs[
Object.keys(daysTogether).reduce((a, b) =>
daysTogether[a] > daysTogether[b] ? a : b
)
];
}
This solution should be O(n log n).
for each record
group record by project id
for each stored record in this group, compare to current record
compare the worked together time to the longest for this group, if it's greater update longest
add current record to stored records in this group
The deObjectify cleanup is not strictly necessary
const data = [
[1,2,"2019-12-25","2020-12-28"],
[1,3,"2018-10-12",null],
[1,4,"2019-11-16",null],
[1,5,"2020-1-5","2020-12-21"],
[2,1,"2018-10-3",null],
[2,2,"2019-1-16","2020-3-24"],
[2,3,"2019-5-22","2019-12-26"],
[2,4,"2020-3-7",null],
[2,5,"2018-1-24","2019-1-15"],
[3,1,"2019-3-21","2020-11-26"],
[3,5,"2019-9-28","2020-12-25"],
[4,2,"2018-10-22",null],
[4,3,"2018-1-27","2020-8-28"],
[5,3,"2018-2-3","2020-10-14"],
[5,5,"2018-8-4",null]
];
const overlap = (e1d1, e1d2, e2d1, e2d2) => {
const startDate1 = new Date(e1d1);
const endDate1 = e1d2 === null ? new Date() : new Date(e1d2);
const startDate2 = new Date(e2d1);
const endDate2 = e2d2 === null ? new Date() : new Date(e2d2);
const start = startDate1 < startDate2 ? startDate2 : startDate1;
const end = endDate1 < endDate2 ? endDate1 : endDate2;
if (end >= start) {
const diffTime = Math.abs(end - start);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
}
return 0;
};
const result = data.reduce((acc, el) => {
let c = acc[el[1]];
if (!c) {
c = acc[el[1]] = {
overlap: 0,
e1: 0,
e2: 0,
data: []
};
};
c.data.forEach(d => {
const o = overlap(d[2], d[3], el[2], el[3]);
if (o > c.overlap) {
c.overlap = o;
c.e1 = d[0];
c.e2 = el[0];
}
});
c.data.push(el);
return acc;
}, {});
const deObjectify = Object.entries(result).map(([projectId, {e1, e2, overlap}]) => ({e1, e2, projectId, overlap}));
console.log(deObjectify);
console.log("inner workings");
console.log(result);
So this is my final code...
Result:
[ { emA: 1, emB: 2, sum: 1230, details: [{ proj: 1, days: 407 }, { proj: 2, days: 90 }, { proj: 3, days: 219 }, { proj: 4, days: 514 }]}
, { emA: 1, emB: 5, sum: 1084, details: [{ proj: 3, days: 733 }, { proj: 5, days: 351 }]}
, { emA: 1, emB: 4, sum: 1055, details: [{ proj: 2, days: 369 }, { proj: 3, days: 686 }]}
, { emA: 4, emB: 5, sum: 937, details: [{ proj: 3, days: 937 } ]}
, { emA: 1, emB: 3, sum: 758, details: [{ proj: 1, days: 407 }, { proj: 5, days: 351 }]}
, { emA: 2, emB: 4, sum: 652, details: [{ proj: 2, days: 433 }, { proj: 3, days: 219 }]}
, { emA: 2, emB: 3, sum: 616, details: [{ proj: 1, days: 616 } ]}
, { emA: 3, emB: 5, sum: 455, details: [{ proj: 5, days: 455 } ]}
, { emA: 2, emB: 5, sum: 384, details: [{ proj: 3, days: 219 }, { proj: 5, days: 165 }]}
]
const data =
[ [ 1, 1, '2019-7-4', '2020-8-14' ]
, [ 1, 2, '2019-12-25', '2020-12-28' ] // EmployeeID, ProjectID, StartDate, EndDate(null === today)
, [ 1, 3, '2018-10-12', null ]
, [ 1, 4, '2019-11-16', null ]
, [ 1, 5, '2020-1-5', '2020-12-21' ]
, [ 2, 1, '2018-10-3', null ]
, [ 2, 2, '2019-1-16', '2020-3-24' ]
, [ 2, 3, '2019-5-22', '2019-12-26' ]
, [ 2, 4, '2020-3-7', null ]
, [ 2, 5, '2018-1-24', '2019-1-15' ]
, [ 3, 1, '2019-3-21', '2020-11-26' ]
, [ 3, 5, '2019-9-28', '2020-12-25' ]
, [ 4, 2, '2018-10-22', null ]
, [ 4, 3, '2018-1-27', '2020-8-28' ]
, [ 5, 3, '2018-2-3', '2020-10-14' ]
, [ 5, 5, '2018-8-4', null ]
]
const
oneDay = 24 * 60 * 60 * 1000 // hours*minutes*seconds*milliseconds
, setDate = YMD =>
{
let [Y,M,D] = YMD.split('-').map(Number)
return new Date(Y,--M,D)
}
// group Employees by project id , change date string to JS newDate
const Proj_Emps = data.reduce( (r,[EmployeeID, ProjectID, StartDate, EndDate])=>
{
let stD = setDate(StartDate)
, enD = EndDate ? setDate(EndDate) : new Date()
r[ProjectID] = r[ProjectID] ?? []
r[ProjectID].push({EmployeeID,stD,enD})
return r
}, {})
// combination of pairs of employees per project
let combination = {}
for (let proj in Proj_Emps)
for (let i = 0; i < Proj_Emps[proj].length - 1; i++)
for (let j = i + 1; j < Proj_Emps[proj].length; j++)
{
let emA = Proj_Emps[proj][i]
let emB = Proj_Emps[proj][j]
if (( emA.enD <= emB.enD && emA.enD > emB.stD )
||( emB.enD <= emA.enD && emB.enD > emA.stD )
){
let
D1 = emA.stD > emB.stD ? emA.stD : emB.stD
, D2 = emA.enD < emB.enD ? emA.enD : emB.enD
, days = Math.ceil((D2 - D1) / oneDay)
, key = `${emA.EmployeeID}-${emB.EmployeeID}`
;
combination[key] = combination[key] ?? { emA: emA.EmployeeID, emB: emB.EmployeeID, sum:0, details:[] }
combination[key].details.push({proj: Number(proj), days })
combination[key].sum += days
}
}
let Result =
Object.entries(combination)
.sort((a,b)=> b[1].sum - a[1].sum )
.map(([k,v])=>v)
Result.forEach(el => console.log( JSON.stringify(el).replaceAll('"','')))
.as-console-wrapper { max-height: 100% !important; top: 0 }
.as-console-row::after { display: none !important; }
I also fixed a bugg (typo) on the calculation of dates

How to update value in array based on values in another array?

I am having two array like this,
let array1 = [
{
"id": 23,
"name": "Telangana",
}
]
Here i need to update array2 color value inside properties based on array1 numberOfProjects value inside latestMetric. As u can see that in both arrays stateId and id are same.If numberOfProjects value is in the range 1 - 1000. I need to update the color value as 1. then numberOfProjects value is in the range 1000 - 2000. I need to update the color value as 2.so on. I dont know how to achieve this. I tried to map those two arrays and can able to get the ID's.But i dont know how to compare them and update the value . Pleas help me.Thanks in advance
You can do like this
let updatedArr2 = [];
function updateArr2(arr2values, colorValue) {
let updatedProperties = { ...arr2values.properties, color: colorValue };
arr2values.properties = updatedProperties;
updatedArr2.push(arr2values);
}
array2.map(arr2values =>
array1.map(arr1values => {
if (arr2values.properties.stateId === arr1values.latestMetric.stateId) {
if (
arr1values.latestMetric.numberOfProjects >= 1 &&
arr1values.latestMetric.numberOfProjects <= 1000
) {
updateArr2(arr2values, 1);
} else if (
arr2values.latestMetric.numberOfProjects >= 1000 &&
arr2values.latestMetric.numberOfProjects <= 2000
) {
updateArr2(arr2values, 2);
}
}
})
);
console.log(updatedArr2);
You could loop through each object in array1 and then check if there's any object in array2 that matches the stateId, if so, then check the number of projects in the array1 object and change the color of the object in array2 that has the same stateId, something like:
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
let array1 = [
{
id: 23,
name: "Telangana",
code: "lnn",
regionId: 1,
isActive: true,
latitude: 17.8495919,
longitude: 79.1151663,
latestMetric: {
stateId: 23,
year: 0,
constructionValueInMn: 84623,
constructionAreaInMnSqft: 32,
numberOfProjects: 406,
noOfCompletedProjects: 19,
noOfOngoingProjects: 387,
noOfUpcomingProjects: 0,
growthRate: 0,
averagePricePerSqftInRs: 0,
totalAreaInMnSqft: 71,
overAllAvgSqft: 0,
eachVariantAvgSqft: 0,
noOfTypeOfVariant: 0,
projectCompletionCycle: 0,
},
createdAt: "2020-04-21T00:35:11.684134",
updatedAt: "2020-04-21T00:35:11.684134",
},
];
let array2 = [
{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[
[77.19721, 28.861519],
[77.203836, 28.86004],
],
],
},
properties: {
cartodb_id: 26,
state_code: 7,
st_nm: "NCT of Delhi",
color: 2,
id: 23,
stateId: 23,
},
},
];
array1.forEach((o) => {
let matches = array2.filter(
(o2) => o2.properties.stateId === o.latestMetric.stateId
);
let projects = o.latestMetric.numberOfProjects;
for (let match of matches) {
if (projects > 1 && projects < 1000) {
match.properties.color = 1;
} else if (projects >= 1000 && projects < 2000) {
match.properties.color = 2;
}
}
});
console.log(array2);
Try this:
array2.map(arr2 => {
//Find to return the position when the id's are the same
const arr1 = array1.find(arr => arr.latestMetric.stateId == arr2.properties.id)
// If find was successful, do this
if (arr1) {
// Destructuring assignment to be easier to compare
const { numberOfProjects } = arr1.latestMetric
if (numberOfProjects >= 1 && numberOfProjects < 1000)
arr2.properties.color = 1
else if (numberOfProjects >= 1000 && numberOfProjects < 2000)
arr2.properties.color = 2
}
})

Stable sort dynamically created array which contains duplicates (javascript)

I've been working on this for a couple of days, looked through all the other threads but can't seem to find a solution to my problem.
I start off with an object array, each specifying a 'start' and 'end' number. I loop through the difference between these, creating a new object from each number in between, storing the 'name' data in each new object created.
After which, I would like to sort the data based off the number, but maintaining the placement order of the original array.
const data = [{
'start': 10,
'finish': 14,
'name': 'one'
}, {
'start': 14,
'finish': 19,
'name': 'two'
}, {
'start': 12,
'finish': 16,
'name': 'three'
}]
let newData = [];
for (let d of data) {
const start = d.start;
const finish = d.finish;
for (let i = start; i <= finish; i++) {
newData.push({
'number': i,
'name': d.name
})
}
}
const sortData = (data) => newData.sort((a, b) => a.number - b.number)
const result = sortData(data)
// Test order for number 14
for(let r of result){
if(r['number'] == 14){
console.log(r.name)
}
}
// Show all data
console.log(result)
Sorry for the long snippet, but it's difficult for me to display the problem.
At the moment, when looking for the items with the number '14' after the sort, the names displayed are 'two, three, one'. I would like to instead maintain the original order of the 'data' array, so it should display as 'one, two, three'.
I'm not sure how sort() is deciding what goes where, because if I change the second object's finish number to 17 inside the original data array it will display the items for number '14' in the correct order.
Just to repeat - I would like to sort the newData array by the number but placed in the order of the original 'data' array.
I hope everything is clear! Please let me know if I can improve the question some how.
Here is a plunkr with the code - http://plnkr.co/edit/tM0h4C93CAnyy1g0T3jp?p=preview.
For a stable sort, you need another propery, like the index of the array.
With a new property,
const data = [{ start: 10, finish: 14, name: 'one' }, { start: 14, finish: 19, name: 'two' }, { start: 12, finish: 16, name: 'three' }]
let newData = [];
data.forEach((d, pos) => {
const start = d.start;
const finish = d.finish;
for (let i = start; i <= finish; i++) {
newData.push({ number: i, name: d.name, pos })
}
});
const sortData = (data) => newData.sort((a, b) => a.number - b.number || a.pos - b.pos)
const result = sortData(data)
// Test order for number 14
for(let r of result){
if(r['number'] == 14){
console.log(r.name)
}
}
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
or sort by name with an object.
const data = [{ start: 10, finish: 14, name: 'one' }, { start: 14, finish: 19, name: 'two' }, { start: 12, finish: 16, name: 'three' }]
let newData = [];
let order = Object.create(null);
data.forEach((d, pos) => {
const start = d.start;
const finish = d.finish;
order[d.name] = pos;
for (let i = start; i <= finish; i++) {
newData.push({ number: i, name: d.name })
}
});
const sortData = (data) => newData.sort((a, b) => a.number - b.number || order[a.name] - order[b.name])
const result = sortData(data)
// Test order for number 14
for(let r of result){
if(r['number'] == 14){
console.log(r.name)
}
}
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories