Get consecutive dates in pairs from array - javascript

I am trying to extract consecutive days pairs from an array. For example:
const arr = [ '2017-06-08', '2017-06-09', '2017-08-22','2017-06-13','2017-06-14','2017-06-15','2017-07-15'];
I would like the following output
[['2017-06-08', '2017-06-09'], ['2017-06-13', '2017-06-14'], ['2017-06-14', '2017-06-15']]
In the above example you can see, if there is more than 2 consecutive days(13, 14, 15), it splits them into pairs of 13 & 14, 14 & 15.
I did get the following example from another question answered
const test = (arr) => {
return arr.reduce(
(acc, date) => {
const group = acc[acc.length - 1];
console.log(group[group.length - 1]);
if (
moment(date).diff(moment(group[group.length - 1] || date), 'days') > 1
) {
acc.push([date]);
} else {
group.push(date);
}
return acc;
},
[[]]
);
};
But it still doesnt quite give the desired output:
[ [ '2017-06-08', '2017-06-09' ],
[ '2017-08-22', '2017-06-13', '2017-06-14', '2017-06-15' ],
[ '2017-07-15' ] ]

You can try the following code:
const test = (arr) => {
let sorted_arr = arr.sort();
let result = [[sorted_arr[0]]];
let j=0;
for(let i=1; i<arr.length; i++) {
var date = sorted_arr[i];
var prev_date = sorted_arr[i-1];
if(moment.duration(moment(date).diff(moment(prev_date))).days() > 1) {
j++;
result.push([date]);
} else {
if(result[j].length == 2) {
j++;
result.push([prev_date, date]);
} else {
result[j].push(date);
}
}
}
return result;
};

Related

How do I write all iterations of reduce to an array?

The idea behind the script is as follows:
I am filtering the original array by removing all even values from it. Next, I form a new array from the partial products of the original array:
// new first element = 1 * 3;
// second = (first (previous multiplication) * current value) = 3 * 3 (9);
// third = (previous product * current value) = 9 * 9 (81)
I got the results I wanted, but my output doesn't look like an array:
Input:
3 3 9
Output:
3
9
81
Please help me draw the following output:
Input:
3 3 9
Output:
3 9 81
function modify(arr) {
var result = [];
arr = arr.filter(item => !(item % 2 == 0))
.reduce(function(acc, curItem) {
console.log(acc * curItem);
return acc * curItem;
}, 1)
for (let i = 0; i < result.length; i++) {
arr.push(result[i]);
};
return result;
}
console.log( modify([3,3,9]) )
You can use reduce keeping track of both your cumulative product, and the final array:
const input = [3, 3, 9];
const output = input.reduce( (acc,val) => {
const newResult = acc.cum * val;
acc.result.push(newResult);
acc.cum = newResult;
return acc;
},{cum:1, result:[]});
console.log(output.result);
As the last element of the array is always the cumulative product, you could also write it like this:
const input = [3, 3, 9];
const output = input.reduce( (acc,val) => {
const newResult = (acc.length ? acc[acc.length-1] : 1) * val;
acc.push(newResult);
return acc;
},[]);
console.log(output);
It's up to you which one of these you find easier to work with.
With Array#reduce() method and the spread operator you can transform your array as in the following demo:
let modify = (arr) => arr.reduce((acc,cur,i) => [...acc, (acc[i-1] || 1) * cur],[]);
console.log( modify([3,3,9]) );
Or simply:
function modify(arr) {
return arr.reduce(function(acc,cur,i) {
return [...acc, (acc[i-1] || 1) * cur]
}, []);
}
console.log( modify([3,3,9]) );
Or if this is code that runs once, in which case you don't need a function:
let oldArray = [3,3,9];
let newArray = oldArray.reduce(function(acc,cur,i) {
return [...acc, (acc[i-1] || 1) * cur]
}, []);
console.log( newArray );

from an array of objects how do I find which value comes up most often, in javascript? [duplicate]

I'm looking for an elegant way of determining which element has the highest occurrence (mode) in a JavaScript array.
For example, in
['pear', 'apple', 'orange', 'apple']
the 'apple' element is the most frequent one.
This is just the mode. Here's a quick, non-optimized solution. It should be O(n).
function mode(array)
{
if(array.length == 0)
return null;
var modeMap = {};
var maxEl = array[0], maxCount = 1;
for(var i = 0; i < array.length; i++)
{
var el = array[i];
if(modeMap[el] == null)
modeMap[el] = 1;
else
modeMap[el]++;
if(modeMap[el] > maxCount)
{
maxEl = el;
maxCount = modeMap[el];
}
}
return maxEl;
}
There have been some developments in javascript since 2009 - I thought I'd add another option. I'm less concerned with efficiency until it's actually a problem so my definition of "elegant" code (as stipulated by the OP) favours readability - which is of course subjective...
function mode(arr){
return arr.sort((a,b) =>
arr.filter(v => v===a).length
- arr.filter(v => v===b).length
).pop();
}
mode(['pear', 'apple', 'orange', 'apple']); // apple
In this particular example, should two or more elements of the set have equal occurrences then the one that appears latest in the array will be returned. It's also worth pointing out that it will modify your original array - which can be prevented if you wish with an Array.slice call beforehand.
Edit: updated the example with some ES6 fat arrows because 2015 happened and I think they look pretty... If you are concerned with backwards compatibility you can find this in the revision history.
As per George Jempty's request to have the algorithm account for ties, I propose a modified version of Matthew Flaschen's algorithm.
function modeString(array) {
if (array.length == 0) return null;
var modeMap = {},
maxEl = array[0],
maxCount = 1;
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
maxEl = el;
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
maxEl += "&" + el;
maxCount = modeMap[el];
}
}
return maxEl;
}
This will now return a string with the mode element(s) delimited by a & symbol. When the result is received it can be split on that & element and you have your mode(s).
Another option would be to return an array of mode element(s) like so:
function modeArray(array) {
if (array.length == 0) return null;
var modeMap = {},
maxCount = 1,
modes = [];
for (var i = 0; i < array.length; i++) {
var el = array[i];
if (modeMap[el] == null) modeMap[el] = 1;
else modeMap[el]++;
if (modeMap[el] > maxCount) {
modes = [el];
maxCount = modeMap[el];
} else if (modeMap[el] == maxCount) {
modes.push(el);
maxCount = modeMap[el];
}
}
return modes;
}
In the above example you would then be able to handle the result of the function as an array of modes.
Based on Emissary's ES6+ answer, you could use Array.prototype.reduce to do your comparison (as opposed to sorting, popping and potentially mutating your array), which I think looks quite slick.
const mode = (myArray) =>
myArray.reduce(
(a,b,i,arr)=>
(arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
null)
I'm defaulting to null, which won't always give you a truthful response if null is a possible option you're filtering for, maybe that could be an optional second argument
The downside, as with various other solutions, is that it doesn't handle 'draw states', but this could still be achieved with a slightly more involved reduce function.
a=['pear', 'apple', 'orange', 'apple'];
b={};
max='', maxi=0;
for(let k of a) {
if(b[k]) b[k]++; else b[k]=1;
if(maxi < b[k]) { max=k; maxi=b[k] }
}
As I'm using this function as a quiz for the interviewers, I post my solution:
const highest = arr => (arr || []).reduce( ( acc, el ) => {
acc.k[el] = acc.k[el] ? acc.k[el] + 1 : 1
acc.max = acc.max ? acc.max < acc.k[el] ? el : acc.max : el
return acc
}, { k:{} }).max
const test = [0,1,2,3,4,2,3,1,0,3,2,2,2,3,3,2]
console.log(highest(test))
Trying out a declarative approach here. This solution builds an object to tally up the occurrences of each word. Then filters the object down to an array by comparing the total occurrences of each word to the highest value found in the object.
const arr = ['hello', 'world', 'hello', 'again'];
const tally = (acc, x) => {
if (! acc[x]) {
acc[x] = 1;
return acc;
}
acc[x] += 1;
return acc;
};
const totals = arr.reduce(tally, {});
const keys = Object.keys(totals);
const values = keys.map(x => totals[x]);
const results = keys.filter(x => totals[x] === Math.max(...values));
This solution has O(n) complexity:
function findhighestOccurenceAndNum(a) {
let obj = {};
let maxNum, maxVal;
for (let v of a) {
obj[v] = ++obj[v] || 1;
if (maxVal === undefined || obj[v] > maxVal) {
maxNum = v;
maxVal = obj[v];
}
}
console.log(maxNum + ' has max value = ' + maxVal);
}
findhighestOccurenceAndNum(['pear', 'apple', 'orange', 'apple']);
For the sake of really easy to read, maintainable code I share this:
function getMaxOcurrences(arr = []) {
let item = arr[0];
let ocurrencesMap = {};
for (let i in arr) {
const current = arr[i];
if (ocurrencesMap[current]) ocurrencesMap[current]++;
else ocurrencesMap[current] = 1;
if (ocurrencesMap[item] < ocurrencesMap[current]) item = current;
}
return {
item: item,
ocurrences: ocurrencesMap[item]
};
}
Hope it helps someone ;)!
Here’s the modern version using built-in maps (so it works on more than things that can be converted to unique strings):
'use strict';
const histogram = iterable => {
const result = new Map();
for (const x of iterable) {
result.set(x, (result.get(x) || 0) + 1);
}
return result;
};
const mostCommon = iterable => {
let maxCount = 0;
let maxKey;
for (const [key, count] of histogram(iterable)) {
if (count > maxCount) {
maxCount = count;
maxKey = key;
}
}
return maxKey;
};
console.log(mostCommon(['pear', 'apple', 'orange', 'apple']));
Time for another solution:
function getMaxOccurrence(arr) {
var o = {}, maxCount = 0, maxValue, m;
for (var i=0, iLen=arr.length; i<iLen; i++) {
m = arr[i];
if (!o.hasOwnProperty(m)) {
o[m] = 0;
}
++o[m];
if (o[m] > maxCount) {
maxCount = o[m];
maxValue = m;
}
}
return maxValue;
}
If brevity matters (it doesn't), then:
function getMaxOccurrence(a) {
var o = {}, mC = 0, mV, m;
for (var i=0, iL=a.length; i<iL; i++) {
m = a[i];
o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
if (o[m] > mC) mC = o[m], mV = m;
}
return mV;
}
If non–existent members are to be avoided (e.g. sparse array), an additional hasOwnProperty test is required:
function getMaxOccurrence(a) {
var o = {}, mC = 0, mV, m;
for (var i=0, iL=a.length; i<iL; i++) {
if (a.hasOwnProperty(i)) {
m = a[i];
o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
if (o[m] > mC) mC = o[m], mV = m;
}
}
return mV;
}
getMaxOccurrence([,,,,,1,1]); // 1
Other answers here will return undefined.
Here is another ES6 way of doing it with O(n) complexity
const result = Object.entries(
['pear', 'apple', 'orange', 'apple'].reduce((previous, current) => {
if (previous[current] === undefined) previous[current] = 1;
else previous[current]++;
return previous;
}, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0];
console.log("Max value : " + result);
function mode(arr){
return arr.reduce(function(counts,key){
var curCount = (counts[key+''] || 0) + 1;
counts[key+''] = curCount;
if (curCount > counts.max) { counts.max = curCount; counts.mode = key; }
return counts;
}, {max:0, mode: null}).mode
}
Another JS solution from: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Can try this too:
let arr =['pear', 'apple', 'orange', 'apple'];
function findMostFrequent(arr) {
let mf = 1;
let m = 0;
let item;
for (let i = 0; i < arr.length; i++) {
for (let j = i; j < arr.length; j++) {
if (arr[i] == arr[j]) {
m++;
if (m > mf) {
mf = m;
item = arr[i];
}
}
}
m = 0;
}
return item;
}
findMostFrequent(arr); // apple
This solution can return multiple elements of an array in case of a tie. For example, an array
arr = [ 3, 4, 3, 6, 4, ];
has two mode values: 3 and 6.
Here is the solution.
function find_mode(arr) {
var max = 0;
var maxarr = [];
var counter = [];
var maxarr = [];
arr.forEach(function(){
counter.push(0);
});
for(var i = 0;i<arr.length;i++){
for(var j=0;j<arr.length;j++){
if(arr[i]==arr[j])counter[i]++;
}
}
max=this.arrayMax(counter);
for(var i = 0;i<arr.length;i++){
if(counter[i]==max)maxarr.push(arr[i]);
}
var unique = maxarr.filter( this.onlyUnique );
return unique;
};
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
};
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
const frequence = (array) =>
array.reduce(
(acc, item) =>
array.filter((v) => v === acc).length >=
array.filter((v) => v === item).length
? acc
: item,
null
);
frequence([1, 1, 2])
var array = [1, 3, 6, 6, 6, 6, 7, 7, 12, 12, 17],
c = {}, // counters
s = []; // sortable array
for (var i=0; i<array.length; i++) {
c[array[i]] = c[array[i]] || 0; // initialize
c[array[i]]++;
} // count occurrences
for (var key in c) {
s.push([key, c[key]])
} // build sortable array from counters
s.sort(function(a, b) {return b[1]-a[1];});
var firstMode = s[0][0];
console.log(firstMode);
Here is my solution to this problem but with numbers and using the new 'Set' feature. Its not very performant but i definitely had a lot of fun writing this and it does support multiple maximum values.
const mode = (arr) => [...new Set(arr)]
.map((value) => [value, arr.filter((v) => v === value).length])
.sort((a,b) => a[1]-b[1])
.reverse()
.filter((value, i, a) => a.indexOf(value) === i)
.filter((v, i, a) => v[1] === a[0][1])
.map((v) => v[0])
mode([1,2,3,3]) // [3]
mode([1,1,1,1,2,2,2,2,3,3,3]) // [1,2]
By the way do not use this for production this is just an illustration of how you can solve it with ES6 and Array functions only.
const mode = (str) => {
return str
.split(' ')
.reduce((data, key) => {
let counter = data.map[key] + 1 || 1
data.map[key] = counter
if (counter > data.counter) {
data.counter = counter
data.mode = key
}
return data
}, {
counter: 0,
mode: null,
map: {}
})
.mode
}
console.log(mode('the t-rex is the greatest of them all'))
Here is my solution :-
function frequent(number){
var count = 0;
var sortedNumber = number.sort();
var start = number[0], item;
for(var i = 0 ; i < sortedNumber.length; i++){
if(start === sortedNumber[i] || sortedNumber[i] === sortedNumber[i+1]){
item = sortedNumber[i]
}
}
return item
}
console.log( frequent(['pear', 'apple', 'orange', 'apple']))
Try it too, this does not take in account browser version.
function mode(arr){
var a = [],b = 0,occurrence;
for(var i = 0; i < arr.length;i++){
if(a[arr[i]] != undefined){
a[arr[i]]++;
}else{
a[arr[i]] = 1;
}
}
for(var key in a){
if(a[key] > b){
b = a[key];
occurrence = key;
}
}
return occurrence;
}
alert(mode(['segunda','terça','terca','segunda','terça','segunda']));
Please note that this function returns latest occurence in the array
when 2 or more entries appear same number of times!
With ES6, you can chain the method like this:
function findMostFrequent(arr) {
return arr
.reduce((acc, cur, ind, arr) => {
if (arr.indexOf(cur) === ind) {
return [...acc, [cur, 1]];
} else {
acc[acc.indexOf(acc.find(e => e[0] === cur))] = [
cur,
acc[acc.indexOf(acc.find(e => e[0] === cur))][1] + 1
];
return acc;
}
}, [])
.sort((a, b) => b[1] - a[1])
.filter((cur, ind, arr) => cur[1] === arr[0][1])
.map(cur => cur[0]);
}
console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple']));
console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple', 'pear']));
If two elements have the same occurrence, it will return both of them. And it works with any type of element.
// O(n)
var arr = [1, 2, 3, 2, 3, 3, 5, 6];
var duplicates = {};
max = '';
maxi = 0;
arr.forEach((el) => {
duplicates[el] = duplicates[el] + 1 || 1;
if (maxi < duplicates[el]) {
max = el;
maxi = duplicates[el];
}
});
console.log(max);
I came up with a shorter solution, but it's using lodash. Works with any data, not just strings. For objects can be used:
const mostFrequent = _.maxBy(Object.values(_.groupBy(inputArr, el => el.someUniqueProp)), arr => arr.length)[0];
This is for strings:
const mostFrequent = _.maxBy(Object.values(_.groupBy(inputArr, el => el)), arr => arr.length)[0];
Just grouping data under a certain criteria, then finding the largest group.
Here is my way to do it so just using .filter.
var arr = ['pear', 'apple', 'orange', 'apple'];
function dup(arrr) {
let max = { item: 0, count: 0 };
for (let i = 0; i < arrr.length; i++) {
let arrOccurences = arrr.filter(item => { return item === arrr[i] }).length;
if (arrOccurences > max.count) {
max = { item: arrr[i], count: arrr.filter(item => { return item === arrr[i] }).length };
}
}
return max.item;
}
console.log(dup(arr));
Easy solution !
function mostFrequentElement(arr) {
let res = [];
for (let x of arr) {
let count = 0;
for (let i of arr) {
if (i == x) {
count++;
}
}
res.push(count);
}
return arr[res.indexOf(Math.max(...res))];
}
array = [13 , 2 , 1 , 2 , 10 , 2 , 1 , 1 , 2 , 2];
let frequentElement = mostFrequentElement(array);
console.log(`The frequent element in ${array} is ${frequentElement}`);
Loop on all element and collect the Count of each element in the array that is the idea of the solution
Here is my solution :-
const arr = [
2, 1, 10, 7, 10, 3, 10, 8, 7, 3, 10, 5, 4, 6, 7, 9, 2, 2, 2, 6, 3, 7, 6, 9, 8,
9, 10, 8, 8, 8, 4, 1, 9, 3, 4, 5, 8, 1, 9, 3, 2, 8, 1, 9, 6, 3, 9, 2, 3, 5, 3,
2, 7, 2, 5, 4, 5, 5, 8, 4, 6, 3, 9, 2, 3, 3, 10, 3, 3, 1, 4, 5, 4, 1, 5, 9, 6,
2, 3, 10, 9, 4, 3, 4, 5, 7, 2, 7, 2, 9, 8, 1, 8, 3, 3, 3, 3, 1, 1, 3,
];
function max(arr) {
let newObj = {};
arr.forEach((d, i) => {
if (newObj[d] != undefined) {
++newObj[d];
} else {
newObj[d] = 0;
}
});
let nwres = {};
for (let maxItem in newObj) {
if (newObj[maxItem] == Math.max(...Object.values(newObj))) {
nwres[maxItem] = newObj[maxItem];
}
}
return nwres;
}
console.log(max(arr));
I guess you have two approaches. Both of which have advantages.
Sort then Count or Loop through and use a hash table to do the counting for you.
The hashtable is nice because once you are done processing you also have all the distinct elements. If you had millions of items though, the hash table could end up using a lot of memory if the duplication rate is low. The sort, then count approach would have a much more controllable memory footprint.
var mode = 0;
var c = 0;
var num = new Array();
var value = 0;
var greatest = 0;
var ct = 0;
Note: ct is the length of the array.
function getMode()
{
for (var i = 0; i < ct; i++)
{
value = num[i];
if (i != ct)
{
while (value == num[i + 1])
{
c = c + 1;
i = i + 1;
}
}
if (c > greatest)
{
greatest = c;
mode = value;
}
c = 0;
}
}
You can try this:
// using splice()
// get the element with the highest occurence in an array
function mc(a) {
var us = [], l;
// find all the unique elements in the array
a.forEach(function (v) {
if (us.indexOf(v) === -1) {
us.push(v);
}
});
l = us.length;
while (true) {
for (var i = 0; i < l; i ++) {
if (a.indexOf(us[i]) === -1) {
continue;
} else if (a.indexOf(us[i]) != -1 && a.length > 1) {
// just delete it once at a time
a.splice(a.indexOf(us[i]), 1);
} else {
// default to last one
return a[0];
}
}
}
}
// using string.match method
function su(a) {
var s = a.join(),
uelms = [],
r = {},
l,
i,
m;
a.forEach(function (v) {
if (uelms.indexOf(v) === -1) {
uelms.push(v);
}
});
l = uelms.length;
// use match to calculate occurance times
for (i = 0; i < l; i ++) {
r[uelms[i]] = s.match(new RegExp(uelms[i], 'g')).length;
}
m = uelms[0];
for (var p in r) {
if (r[p] > r[m]) {
m = p;
} else {
continue;
}
}
return m;
}

Javascript Text Statistic Algorithm Improvement

I am trying to solve one algorithm in Javascript where the user requires the input sentence then have to do statistic as the following screenshot
I have done with following code
class TextAnalytics {
getAnalytics(sentence) {
var analyzedResult = {}
var textArray = new Array();
const trimmed = sentence.replace(/\s/g, '').toUpperCase()
for (let i = 0; i < trimmed.length; i++) {
const currentChar = trimmed[i]
if (!analyzedResult[currentChar]) {
analyzedResult[currentChar] = {
count: 1,
prevChar: trimmed[i - 1] ? [trimmed[i - 1]] : [],
nextChar: trimmed[i + 1] ? [trimmed[i + 1]] : [],
index: [i]
}
} else {
analyzedResult[currentChar].count++
trimmed[i - 1] &&
analyzedResult[currentChar].prevChar.push(trimmed[i - 1])
trimmed[i + 1] &&
analyzedResult[currentChar].nextChar.push(trimmed[i + 1])
analyzedResult[currentChar].index.push(i)
}
}
return analyzedResult;
}
getMaxDistance(arr) {
let max = Math.max.apply(null, arr);
let min = Math.min.apply(null, arr);
return max - min;
}
}
var textAnalytics = new TextAnalytics();
console.log(textAnalytics.getAnalytics("its cool and awesome"));
Want to check if there is any other way to solve this problem or any refactoring require
Help will be appreciated.
Thanks
You can write it more elegantly:
class CharStats {
constructor () {
this.prevs = [];
this.nexts = [];
this.indexes = [];
}
add (prev, next, index) {
prev && this.prevs.push(prev);
next && this.nexts.push(next);
this.indexes.push(index);
return this;
}
get count () {
return this.indexes.length;
}
get maxDistance () {
// If the index array is empty, the result will be Infinite.
// But because the algorithm cannot have a situation where
// this class is used without at least one index, this case
// need not be covered.
return Math.max(...this.indexes) - Math.min(...this.indexes);
}
}
const getAnalytics = sentence =>
[...sentence.replace(/\s/g, '').toUpperCase()].reduce((map, cur, i, arr) =>
map.set(cur, (map.get(cur) || new CharStats).add(arr[i - 1], arr[i + 1], i)),
new Map);
console.log(getAnalytics('its cool and awesome'));
1) Convert string to array of chars, remove empty, change to upper case
2) Use reduce, go thru each char and build object 'keys' as Char values to have before, after and index.
3) if Char already exist in object, Append new stats and calculate max-distance.
const getAnalytics = str => {
const caps = Array.from(str.toUpperCase()).filter(x => x.trim());
return caps.reduce((acc, char, i) => {
const prepost = {
before: caps[i-1] || '',
after: caps[i+1] || '',
index: i
};
if (char in acc) {
const chars = [...acc[char].chars, prepost];
const mm = chars.reduce((acc, curr) => ({
max: Math.max(acc.max, curr.index),
min: Math.min(acc.min, curr.index)
}), {max: -Infinity, min: Infinity});
acc[char] = { chars, max_distance: mm.max - mm.min };
} else {
acc[char] = { chars: [prepost], max_distance: 0 };
}
return acc;
}, {});
}
console.log(getAnalytics('its cool and awesome'));

Creating various arrays from a string using LOOPS

I have a string of values
"000111111122222223333333444455556666"
How could I use a loop to produce one array for index values from 0 to 3 (create an array of [000] and then another array of index values from 3 to 10, 10 to 17, 17 to 24, producing eg. [1111111, 2222222, 333333] and then another loop to produce an array of index values from 24 to 28, 28 to 32, 32 to 36, producing eg. [4444, 5555, 6666])?
So in total 3 different arrays have been created using three different for loops.
array1 = [000]
array2 = [1111111, 2222222, 333333]
array3 = [4444, 5555, 6666]
You may wish to try something line this (only a schematic solution!):
var l_Input = "000111111122222223333333444455556666" ;
var l_Array_1 = [] ;
var l_Array_2 = [] ;
var l_Array_3 = [] ;
var l_One_Char ;
for (var i = 0 ; i < l_Input.length ; i++) {
l_One_Char = l_Input.substring(i,i) ;
if (i < 3) {
l_Array_1.push(l_One_Char) ;
continue ;
}
if (i >= 3 && i < 10) {
l_Array_2.push(l_One_Char) ;
continue ;
}
:
:
}
I think this would work.
const str = '000111111122222223333333444455556666';
function makeArr(str, item) {
let firstIndex = str.indexOf(item);
let lastIndex = str.lastIndexOf(item) + 1;
return [ str.substring(firstIndex, lastIndex) ];
}
const first = makeArr(str, 0);
const second = [].concat(makeArr(str, 1))
.concat(makeArr(str, 2))
.concat(makeArr(str, 3));
const third = [].concat(makeArr(str, 4))
.concat(makeArr(str, 3))
.concat(makeArr(str, 3));
You could map the sub strings.
var str = '000111111122222223333333444455556666',
parts = [[3], [7, 7, 7], [4, 4, 4]],
result = parts.map((i => a => a.map(l => str.slice(i, i += l)))(0));
console.log(result);
function split(string, start, end) {
var result = [],
substring = string[start],
split;
for (var i = start + 1; i < end; i++) {
var char = string[i];
if (char === substring[0])
substring += char;
else {
result.push(substring);
substring = char;
}
}
result.push(substring);
return result;
}
split("00011122",0,8)
["000", "111", "22"]
To do this dynamically, you can use .split() and .map() methods to make an array from your string then group this array items by value.
This is how should be our code:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
This will give you an array of separate arrays with similar values each.
Demo:
const str = "000111111122222223333333444455556666";
var groupArrayByValues = function(arr) {
return arr.reduce(function(a, x) {
(a[x] = a[x] || []).push(x);
return a;
}, []);
};
var arr = str.split("").map(v => +v);
var result = groupArrayByValues(arr);
console.log(result);

How to combine consecutive dates in javascript?

I have an array of dates such as :
test = [ '2018-07-18', '2018-07-19', '2018-07-21', '2018-07-23', '2018-07-24', '2018-07-26'];
And I want to return an array of sub arrays of consecutive dates like this:
result = [['2018-07-18', '2018-07-19'], ['2018-07-21'], ['2018-07-23', '2018-07-24'], ['2018-07-26']]
I'm trying to write a snippet code:
const moment = require('moment');
let visited = [];
const alpha = test.reduce((accumlator, current_date, current_index, array) => {
let start_date = current_date;
let successive_date = array[current_index + 1];
visited.push(start_date);
if(successive_date && moment(successive_date).diff(moment(start_date), 'days') === 1
&& visited.includes(successive_date) === false) {
accumlator.concat(start_date);
accumlator.concat(successive_date);
}
if(successive_date && moment(successive_date).diff(moment(start_date), 'days') !== 1
&& visited.includes(successive_date) === false) {
accumlator.concat(successive_date);
}
return accumlator;
}, []);
console.log('alpha: ', alpha);
The result when using concat was:
alpha: []
I used push() and it returns an array such test:
alpha: [ '2018-07-18','2018-07-19','2018-07-21','2018-07-23','2018-07-23','2018-07-24''2018-07-26' ]
How can I fix this in order to get the result such as mentioned above?
You can try with:
test.reduce((acc, date) => {
const group = acc[acc.length - 1];
if (moment(date).diff(moment(group[group.length - 1] || date), 'days') > 1) {
acc.push([date])
} else {
group.push(date);
}
return acc;
}, [[]])
Output:
[
[
"2018-07-18",
"2018-07-19"
],
[
"2018-07-21"
],
[
"2018-07-23",
"2018-07-24"
],
[
"2018-07-26"
]
]
Th following helps, if the order of the dates in the array is not maintained. For example, '2018-07-18', '2018-07-19', '2018-07-17' are consecutive but scattered at the start and end of the array.
var test = [ '2018-07-18', '2018-07-19', '2018-07-21', '2018-07-23', '2018-07-24', '2018-07-26', '2018-07-17'], dateformat = "YYYY-MM-DD";
var result = test.reduce(function(acc,val){
var present, date = moment(val,dateformat);
acc.forEach(function(arr,index){
if(present) return;
if(arr.indexOf(date.clone().subtract(1,'day').format(dateformat))>-1 || arr.indexOf(date.clone().add(1,'day').format(dateformat))>-1)
{
present = true;
arr.push(val);
}
});
if(!present) acc.push([val]);
return acc;
},[]);
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
You can use this function but dates should be in sorted order.
function get_relative_dates(dates){
var format = 'YYYY-MM-DD';
var newDate = [];
dates.forEach(function(date){
var lastArr, lastDate;
if(newDate.length){
lastArr = newDate[newDate.length -1];
if(!lastArr.length)
lastArr.push(date);
else{
var lastDate = lastArr[lastArr.length -1];
if(moment(lastDate, format).add(1,'d').format(format) == date)
lastArr.push(date);
else
newDate.push([date]);
}
}
else
newDate.push([date]);
});
return newDate;
}

Categories

Resources