最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I extract numbers sequence from array? - Stack Overflow

programmeradmin5浏览0评论

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
Add a ment  | 

8 Answers 8

Reset to default 4

One 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.reduceand 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() ) ) );

发布评论

评论列表(0)

  1. 暂无评论