How to dynamically slice Array in Javascript - javascript

I have a month array in javascript, for example:
2012/09/01,2012/10/01,2012/11/01,2012/12/01,2013/01/01,2013/02/01,2013/03/01,
2012/09/01,2012/10/01,2012/11/01,2012/12/01,2013/01/01,2013/02/01,2013/03/01,2013/04/01,
2012/09/01,2012/10/01,2012/11/01,2012/12/01
What I wanna separate the Array is that:
if (monthArray[i] > monthArray[i + 1])
// slice the Array.
So, for the above example, I should get 3 new Arrays. They are:
Array1: 2012/09/01,2012/10/01,2012/11/01,2012/12/01,2013/01/01,2013/02/01,2013/03/01
Array2: 2012/09/01,2012/10/01,2012/11/01,2012/12/01,2013/01/01,2013/02/01,2013/03/01,2013/04/01
Array3:2012/09/01,2012/10/01,2012/11/01,2012/12/01
I know it is easy to do it if we know specific length, my question is, how to do it if we dynamically get a month Array(it may be divided into n groups). How to do that? Thanks!

I don't know of any better way than to iterate over the array to build your slices:
var arr = ['2012/09/01','2012/10/01','2012/11/01','2012/12/01','2013/01/01','2013/02/01','2013/03/01','2012/09/01','2012/10/01','2012/11/01','2012/12/01','2013/01/01','2013/02/01','2013/03/01','2013/04/01','2012/09/01','2012/10/01','2012/11/01','2012/12/01'];
var slices = [];
var start = 0;
for (var i=0; i<arr.length; i++) {
if (check(arr, i)) {
slices.push(arr.slice(start, i+1));
start = i+1;
}
}
function check(array, index) {
if (index+1 === array.length) return true;
return Date.parse(array[index]) > Date.parse(array[index+1]);
}
This solution has the advantage that it doesn't build the slices one element at a time, instead it builds them one slice at a time.

Assuming you want an array-of-arrays as a result, you can do this with .reduce:
var partitions = dateList.reduce(function(rv, month) {
var partition = rv[rv.length - 1], prevMonth = partition[partition.length - 1];
if (!prevMonth || prevMonth < month)
partition.push(month);
else
rv.push([month]);
return rv;
}, [ [] ]);
Starting from a list of partitions with one (empty) partition, this just checks the last month in the last partition to see if it's smaller than the current month under examination. If so (or if we're on the very first one), we add the month onto the partition. If not, then a new partition is started, containing just the current month.

So assuming you want to end up with an array of arrays, then just do it with a for loop...
var result = []; //this will contain multiple arrays once finished
var currentArray = [];
for (var i = 0; i < monthArray.length; i++) {
currentArray.push(monthArray[i]);
if (i < monthArray.length - 1 && monthArray[i] > monthArray[i + 1]) {
result.push(currentArray);
currentArray = [];
}
}
result.push(currentArray);
//result[0] is Array1
//result[1] is Array2
//result[2] is Array3
Here is a working example

Related

How to compare and extract arrays inside of another array

I am writing a program that needs to compare different birthday dates in an array, and the array is like this:
birthdays = [1, [11,2], 2, [2,4], 3, [11,2], 4, [3,5], 5, [6,7], 6, [3,5], 7, [8,9]..]
The even index stores the number of student, and the odd positions store their birthday date in the form of an array[month, day]. I need to return an array of number of students who have unique birthday dates(their birthday dates only appeared once in the array).
Here is my effort so far:
function find(birthdays) {
let array2 = birthdays.slice();
let unique_arr = [];
let element_comp;
for (let i = 0; i < birthdays.length; i++) {
birthdays.splice(i,1)//birthdays
array2.splice(i+1,1)//numbers
}
for(let i = 0; i < birthdays.length; i++){
element_comp = birthdays[i];
for(let j = 0; j < birthdays.length; j++){
if(i !== j &&element_comp.toString == birthdays[j].toString){
break;
}
if(j === birthdays.length - 1){
unique_arr.push(array2[i])
}
}
}
return unique_arr;
}
My idea is to break the array into to two sub-arrays, one stores the numbers and the other one stores the birthday dates. Then I compared the element of the birthday date array one by one to see if they are unique. If I find a same date, I break out of the inner and start to compare the next one, otherwise if the inner index reaches the end of the array I stores the element of the number array of the same index into another array that will be returned
Expected Result:[2, 5, 7...]
But it didn't work as expected because it would break out of the array each time and never store the element. Please explain to me where I did wrong, thank you
You can do it with dictiory. without having nested loop
loop on element and see if month and date combination month_date exist in dict append the students to it else create a new key with month_date and append to dict with value of array of current student
after this loop complete you can loop over dict key values and and see if any key having single value then take those values.
function find(birthdays) {
let unique_dates = {}
for (let i = 0; i < birthdays.length; i+=2) {
let key = `${birthdays[i+1][0]}_${birthdays[i+1][1]}`
if (!(key in unique_dates)) {
unique_dates[key] = []
}
unique_dates[key].push(birthdays[i])
}
let unique_arr = [];
for (let unique_date in unique_dates){
if (unique_dates[unique_date].length == 1) {
unique_arr.push(unique_dates[unique_date][0])
}
}
return unique_arr;
}

matching items from two list in nodejs

my current problem is I have two mongodb collections. My code in essence takes each name from table 1 which is 250000~ items then it compares against the list of names from table 2 (3000~) to try and match.
now I'm just brute forcing this by going through every item in the 250000 list and looking at every item in the 3000 list to see if it matches
the problem is that this takes about 2 hours to run through
Is there a faster way to do matching? I've put the stripped down version of my code below so you can see it's a simple loop in a loop.
Thanks
const SCCM = await ProgramDev.find({})
const Cat = await Software.find({})
for (var i = 0, len = SCCM.length; i < len; i++) {
for (var n = 0, Catlen = Cat.length; n < Catlen; n++) {
var program = SCCM[i]['program name']
var software = Cat[n]['Application']
var sat = Cat[n].Status
if (SCCM[i].Status == undefined) {
if (program == software) {
SCCM[i].Status = sat
break
}
}
}
if (SCCM[i].Status == undefined) {
SCCM[i].Status = "Un-authorised"
SCCM[i].matchType = "None"
}
}
If you have already extracted each name from collection1 and from collection2 into arrays this should work faster
array1 = ['john','smith','vova','putin', 'eug', 'hilly', 'tom', 'smith','vova','putin' ]
array2 = ['vova', 'dr.cacis']
const newArray = array1.filter(value => array2.includes(value));
console.log(newArray);
Output matches
[ 'vova', 'vova' ]
You can also use Array.prototype.includes
or Array.prototupe.indexOf
You can try to use map if you don't have memory restriction and put the values of Cat in the map like:
var catMap = new Map();
for (var n = 0, Catlen = Cat.length; n < Catlen; n++) {
catMap.set(Cat[n]['Application'] , Cat[n].Status);
}
And run the second loop on SCCM like:
for (var i = 0, len = SCCM.length; i < len; i++) {
if (SCCM[i].Status == undefined && catMap.has(SCCM[i]['program name'])){
SCCM[i].Status = catMap.get(SCCM[i]['program name']);
}else if(SCCM[i].Status == undefined){
SCCM[i].Status = "Un-authorised"
SCCM[i].matchType = "None"
}
}
So, the first loop will take O(n) and second loop will take O(m), total will be O(m+n) time complexity.
The space complexity will be O(n) because of map.
Overall, program will take less time to run.

add sum of previous to array - javascript

In a multi-dimensional array, how can I add a new dimension that is the sum of all of previous values of one of the other dimensions?
What I have:
var myarray = [[5,"a"],[10,"a"],[3,"a"],[2,"a"]];
What I want:
var newArray = [[5,"a",5],[10,"a",15],[3,"a",18],[2,"a",20]];
I am trying to turn this example (second answer, second code block):
var myarray = [5, 10, 3, 2];
var result = myarray.reduce(function(r, a) {
if (r.length > 0)
a += r[r.length - 1];
r.push(a);
return r;
}, []);
// [5, 15, 18, 20]
And apply it like this:
var myarray = [[5,"a"],[10,"a"],[3,"a"],[2,"a"]];
var result = myarray.reduce(function(r, a) {
if (r.length > 0)
a += r[0][r.length - 1];
r[2].push(a);
return r;
}, []);
// [[5,"a",5],[10,"a",15],[3,"a",18],[2,"a",20]];
But I can't find an effective way to separate out the first value in order to run reduce on it. I tried foreach, but that isn't returning an array:
var firstValue = myarray.forEach(function(value, index) {
console.log(value[0]);
})
So, I'm thinking take that foreach output and turn it into an array somehow to operate on, then push it back in. But it's seeming very convoluted. Can anyone point me in the right direction?
Thanks.
For reducing the array and only pulling the first element from each array, you actually need to build an array with the foreach loop.
Create an array outside the loop and use array.push(value) to build the other array.
var firstValues = [];
myarray.forEach(function(value, index) {
firstValues.push(value);
});
My preferred solution:
Since you're already looping through the array, you can instead do a lot of the logic within just one loop.
var currentSum = 0;
myarray.forEach(function(value, index) {
currentSum += value[0]; //add to the running sum
value.push(currentSum); //append the running sum to the end of this inner array
});
Here's a demo via jsfiddle
a simple for loop should do it
var sum = 0;
for (var i = 0; i < myarray.length; i++) {
sum = sum + (myarray[i][0]);
myarray[i].push(sum);
}
console.log(myarray);
Fiddle link

Sort Array in special manner

I have a problem sorting an array. I am not the smartest concerning these sort algorithms.
The array should have following structure:
var arr = [
[week, IssuesPriority1, IssuesPriority2, IssuesPriority3],
[week, IssuesPriority1, IssuesPriority2, IssuesPriority3],
[week, IssuesPriority1, IssuesPriority2, IssuesPriority3],
...
];
So for each week there is a number of issues for the priority very high, high, medium.
The string that needs to be parsed in this structure is following:
var string =
"26|3|1,27|6|1,28|7|1,29|2|1,30|2|1,31|2|1,32|2|1,33|3|1,
35|1|1,34|2|1,36|0|1,37|0|1,38|1|1,26|11|2,27|10|2,28|9|2,
29|13|2,30|10|2,31|8|2,32|10|2,33|12|2,34|14|2,35|11|2,
36|11|2,37|12|2,38|14|2,27|17|3,26|13|3,29|26|3,28|21|3,30|25|3,
31|20|3,34|30|3,32|18|3,33|25|3,35|33|3,36|28|3,38|28|3,37|27|3";
var arr = string.split(",");
for(var i = 0; i < arr.length; i++){
var currentArr = arr[i].split("|");
var week = currentArr[0];
var issues = currentArr[1];
var priority = currentArr[2];
}
I have a lack of ideas sorting it in the desired way. Can you help me?
I don't think you want any sorting at all. You are looking for grouping!
var arr = string.split(",");
var weeks = {};
for (var i = 0; i < arr.length; i++) {
var currentArr = arr[i].split("|");
var week = currentArr[0];
var issue = currentArr[1];
var priority = currentArr[2];
if (!(week in weeks))
weeks[week] = {1:[], 2:[], 3:[]};
// if the number of issues levels were unknown,
// you'd start with an empty object instead
// and create the arrays dynamically in a manner similar to the weeks
weeks[week][priority].push(issue);
}
return Object.keys(weeks).map(function(week) {
return [week, weeks[week][1], weeks[week][2], weeks[week][3]];
});
(to get the result ordered by week number, add a sort(function(a,b){return a-b}) before the .map() call)
In your situation I would recommand to put the values in the array first. In the second step I would sort the array using the sort method.
function getSortedArrayByString(myString) {
var arraySplittedString, i, tmpValueArray, tmpInnerArray, resultingArray;
arraySplittedString = myString.split(",");
resultingArray = [];
for(i = 0; i < arraySplittedString.length; i++){
// tmpArray has the format of [<week>, <IssuesPriority1>, <IssuesPriority2>]
tmpValueArray = arraySplittedString[i].split("|");
// Push it in the new array.
resultingArray.push(tmpValueArray);
}
// Sort array by weeks ascending.
resultingArray.sort( function (a, b) {
return a[0] - b[0];
});
return resultingArray;
}
Running fiddle.
If you also want to sort by the count of issues, you simply can customize the inner sort function.
With this solution all values are saved as strings. You can convert them by using the parseInt function.

Fill empty array

I need to iterate from 0 to 30, but I want to do this with help of forEach:
new Array(30).forEach(console.log.bind(console);
Of course this does not work, therefor I do:
new Array(30).join(',').split(',').forEach(console.log.bind(console));
Is there other ways to fill empty arrays?
Actually, there's a simple way to create a [0..N) (i.e., not including N) range:
var range0toN = Object.keys(Array.apply(0,Array(N)));
Apparently Object.keys part can be dropped if you only want to get a proper array of N elements.
Still, like others said, in this particular case it's probably better to use for loop instead.
if you want all of item have same value, do this
var arrLength = 4
var arrVal = 0
var newArr = [...new Array(arrLength)].map(x => arrVal);
// result will be [0, 0, 0, 0]
You could try using a for loop. new Array is not a best practise
var index, // we use that in the for loop
counter, // number of elements in array
myArray; // the array you want to fill
counter = 30;
myArray = [];
for (index = 0; index < counter; index += 1) {
myArray[index] = [];
/*
// alternative:
myArray.push([]);
// one-liner
for (index = 0; index < counter; index += 1) myArray.push([]);
*/
}
If you simply want to iterate, then use for loop like this
for (var i = 0; i < 30; i += 1) {
...
...
}
Actually, if you are looking for a way to create a range of numbers, then you can do
console.log(Array.apply(null, {length: 30}).map(Number.call, Number));
It will create numbers from 0 to 29. Source : Creating range in JavaScript - strange syntax
If you insist foreach
var data = [1, 2, 3];
data.forEach(function(x) {
console.log(x);
});

Categories

Resources