I have the following array :
var selectedRange = [
null,
null,
null,
null,
null,
null,
null,
null,
9, //sequences
10,//sequences
null,
12,
13,
14,
null,
null,
null,
null,
null,
20,
null,
null,
null,
null,
25,
null,
null,
null,
29,
30,
31,
32,
null,
null,
null,
null,
37,
38,
null,
40,
41,
42,
null,
44,
null,
null,
47,
null,
49,
50,
null,
null,
null,
null,
null,
null
]
I need to extract sequences of number and only numbers - so the result would be like:
["9,10", "12,13,14", "20", "25", "29,30,31,32", "44", "47", "49,50"]
The problem is that I can't e up with a solution to extract a sequence as it is, I guess I need a recursive function that repeats the part of checking if the last number and the current are following - like here ...(!!prm && (prm - (index-1) ==1 )
let tempArr = [];
$.each(selectedRange, function (index, prm) {
if (!!prm && (prm - (index - 1) == 1) {
tempArr.push(prm); // need to loop this section with recursion
}
});
I have the following array :
var selectedRange = [
null,
null,
null,
null,
null,
null,
null,
null,
9, //sequences
10,//sequences
null,
12,
13,
14,
null,
null,
null,
null,
null,
20,
null,
null,
null,
null,
25,
null,
null,
null,
29,
30,
31,
32,
null,
null,
null,
null,
37,
38,
null,
40,
41,
42,
null,
44,
null,
null,
47,
null,
49,
50,
null,
null,
null,
null,
null,
null
]
I need to extract sequences of number and only numbers - so the result would be like:
["9,10", "12,13,14", "20", "25", "29,30,31,32", "44", "47", "49,50"]
The problem is that I can't e up with a solution to extract a sequence as it is, I guess I need a recursive function that repeats the part of checking if the last number and the current are following - like here ...(!!prm && (prm - (index-1) ==1 )
let tempArr = [];
$.each(selectedRange, function (index, prm) {
if (!!prm && (prm - (index - 1) == 1) {
tempArr.push(prm); // need to loop this section with recursion
}
});
Share
Improve this question
edited Nov 19, 2020 at 11:26
Emin Mesic
1,8112 gold badges10 silver badges19 bronze badges
asked Nov 19, 2020 at 8:23
RoyBarOnRoyBarOn
9973 gold badges29 silver badges77 bronze badges
5
- do you have the first array and want the second or vice versa? – Nina Scholz Commented Nov 19, 2020 at 8:24
- @NinaScholz - i've updated the question - check it out - thanks – RoyBarOn Commented Nov 19, 2020 at 8:27
-
JSON.stringify(selectedRange).match(/([^null, ])+/g)
would be an interesting start – mplungjan Commented Nov 19, 2020 at 8:30 - can you work with array of arrays instead of putting sequences in a string? – Akash Sarode Commented Nov 19, 2020 at 8:40
- why not just filter out null elements? @mplungjan – Akash Sarode Commented Nov 19, 2020 at 8:41
8 Answers
Reset to default 4One option is to join into a ma delimited string and then split apart the empty elements. Add a final filter to remove leading or trailing empty elements. This might not be the most efficient.
var selectedRange = [null, null, null, null, null, null, null, null, 9, 10, null, 12, 13, 14, null, null, null, null, null, 20, null, null, null, null, 25, null, null, null, 29, 30, 31, 32, null, null, null, null, 37, 38, null, 40, 41, 42, null, 44, null, null, 47, null, 49, 50, null, null, null, null, null, null ]
console.log(
selectedRange.join(',').split(/,,+|^,|,$/).filter(Boolean)
)
(Edited to incorporate ment-suggestions from @KooiInc and @Ifaruki.)
You could iterate the array and have a look to the predecessor.
let selectedRange = [null, 8, null, null, null, 9, 10, null],
result = [],
last;
for (const value of selectedRange) {
if (value === null) continue;
if (last + 1 === value) result[result.length - 1] += `,${value}`;
else result.push(value.toString());
last = value;
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Array.prototype.reduce
to do this operation as follows.
var selectedRange = [ null, null, null, null, null, null, null, null, 9, 10, null, 12, 13, 14, null, null, null, null, null, 20, null, null, null, null, 25, null, null, null, 29, 30, 31, 32, null, null, null, null, 37, 38, null, 40, 41, 42, null, 44, null, null, 47, null, 49, 50, null, null, null, null, null, null ];
let split = null;
const output = selectedRange.reduce((acc, cur) => {
if (cur) {
split ? split += "," + cur : split = `${cur}`;
} else {
if (split) {
acc.push(split);
split = null;
}
}
return acc;
}, []);
console.log(output);
strong text
You can do the following,
var selectedRange = [ null, null, null, null, null, null, null, null, 9, 10, null, 12, 13, 14, null, null, null, null, null, 20, null, null, null, null, 25, null, null, null, 29, 30, 31, 32, null, null, null, null, 37, 38, null, 40, 41, 42, null, 44, null, null, 47, null, 49, 50, null, null, null, null, null, null ];
let isNullSeq = true;
const arr = [];
let temp = '';
selectedRange.forEach((item) => {
if (item) {
if (isNullSeq) {
temp = temp + item;
isNullSeq = false;
} else {
temp += ',';
temp += item;
}
} else {
if (!isNullSeq) {
isNullSeq = true;
arr.push(temp);
temp = '';
}
}
});
console.log(arr);
I would probably use takeWhile
and dropWhile
, you can get them from an utility library like Ramda or implement them by yourself.
const inputs = [
[1,2,null,null,5,6,7,null,null,10,11],
[null,null,3,4,null],
[1,2,null,null,5,null,null],
[null],
[1],
[null, 1],
[],
];
const takeWhile = (predicate) => ([head, ...tail]) => {
if (head === undefined || !predicate (head)) return [];
return [head].concat (takeWhile (predicate) (tail));
}
const dropWhile = (predicate) => ([head, ...tail]) => {
if (head === undefined) return [];
if (!predicate (head)) return [head, ...tail];
return dropWhile (predicate) (tail);
};
const isNull = x => x === null;
const isNotNull = x => x !== null;
const sequence = (list) => {
if (list.length === 0) return [];
if (list[0] === null) return sequence (dropWhile (isNull) (list));
return [takeWhile (isNotNull) (list).join (',')].concat (
sequence (dropWhile (isNotNull) (list))
);
}
console.log (inputs.map (sequence));
.as-console-wrapper { max-height: 100% !important; top: 0; }
if you only have nulls in between - how about something simpler?
var selectedRange = [ null, null, null, null, null, null, null, null, 9, 10, null, 12, 13, 14, null, null, null, null, null, 20, null, null, null, null, 25, null, null, null, 29, 30, 31, 32, null, null, null, null, 37, 38, null, 40, 41, 42, null, 44, null, null, 47, null, 49, 50, null, null, null, null, null, null]
console.log(selectedRange.toString().replace(/,{2,}/g, ',,').split(",,").filter(function(el) { return el != "";}))
By taking into consideration sequence like given in question (9, 10,..., - seq = diff of 1
). Following
code will produce the the required result -
var selectedRange = [
null,
null,
null,
null,
null,
null,
null,
null,
9, //sequences
10,//sequences
null,
12,
13,
14,
null,
null,
null,
null,
null,
20,
null,
null,
null,
null,
25,
null,
null,
null,
29,
30,
31,
32,
null,
null,
null,
null,
37,
38,
null,
40,
41,
42,
null,
44,
null,
null,
47,
null,
49,
50,
null,
null,
null,
null,
null,
null
]
selectedRange = selectedRange.filter(v => v)
var finalArray = [], temp = [];
for(var i=0; i<selectedRange.length; i++)
{
if(selectedRange[i+1]-selectedRange[i] > 1 )
{
temp.push(selectedRange[i]);
finalArray.push(temp.join(","));
temp.length = 0;
}
else temp.push(selectedRange[i])
}
finalArray.push(temp.join(","));
console.log(finalArray);
Create an intermediate array of sequence arrays using Array.reduce
and map the resulting sequences to strings
const selectedRange = [null,null,null,null,null,null,null,null,9, 10,null,12,13,14,null,null,null,null,null,20,null,null,null,null,25,null,null,null,29,30,31,32,null,null,null,null,37,38,null,40,41,42,null,44,null,null,47,null,49,50,null,null,null,null,null,null];
// the reducer lambda
const sequenceReducer = (acc, val) =>
!val ? acc : val - 1 === acc.flat().pop() ?
acc[acc.length-1].push(val) && acc : [...acc, [].concat(val)];
console.log( JSON.stringify( selectedRange.reduce(sequenceReducer, []).map( v => v.join() ) ) );
// let's try discontinuous sequences (numbers are not consecutive)
const x = [null, 8, null, null, null, 9, 10, null, 11, null, null, 12, null, 14, null, 15, null, null, 16];
console.log( JSON.stringify( x.reduce(sequenceReducer, []).map( v => v.join() ) ) );
// sequences are discontinuous AND not ordered. Sort first
// (and by the way, note the negative values)
const y = [26, 13, null, 8, null, -3, null, 9, 25, 10, null, 11, null, 7, 12, null, 14, -2, 15, null, 17, 16, -1];
const sortSequenceArray = (a, b) => +a - +b;
console.log( JSON.stringify( y.sort(sortSequenceArray).reduce(sequenceReducer, []).map( v => v.join() ) ) );