Как преобразовать строку в массив с диапазонами JavaScript

Рассмотрим следующую строку: 7, 20, 22, 30–31, 33, 39–40, 46

Я разработал некоторый код, который будет автоматически анализировать указанную строку в массив с заданными диапазонами следующим образом.

var number_string = "7, 20, 22, 30–31, 33, 39–40, 46".toString().replace(/–/gi, '-').replace(/ /gi, '').split(',');
var new_arr = [];

$.each(number_string, function(index, value) {
  if (value.match(/-/gi)) {
    var range_arr = value.split('-');
    var sub_arr = range(range_arr[0], range_arr[1]);
    $.each(sub_arr, function(sub_index, sub_value) {
      new_arr.push(parseInt(sub_value, 10));
    });
  } else {
    new_arr.push(parseInt(value, 10));
  }
});

console.log(new_arr);

function range(lowEnd, highEnd) {
  var arr = [],
    c = highEnd - lowEnd + 1;
  while (c--) {
    arr[c] = highEnd--
  }
  return arr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Был ли здесь более обтекаемый не jQuery метод, который можно было бы здесь использовать, а также простой, легкий и легко читать? Пожалуйста, не пишите на ES6, потому что это греческое для меня.

Примечание. Функция ToInt - это просто функция, которая возвращает действительное число или 0.

-3
задан Alexander Dixon 26 June 2019 в 22:52
поделиться

2 ответа

Метод jQuery.map() действует как плоская карта (возвращенные вложенные массивы являются плоскими). В функции обратного вызова карты используйте String.search() для проверки наличия тире. Если не конвертировать в число с оператором + и вернуть. Если есть тире, разделите, используйте цикл for для преобразования min и max в массив и возврата массива.

function convert(str) {
  var arr = jQuery.map(str.split(', '), function(s) {
    if(s.search('–') === -1) return +s;
    
    var minmax = s.split('–');
    var range = [];
    
    for(var i = +minmax[0]; i <= +minmax[1]; i++) range.push(i);
    
    return range;
  });
  
  return arr;
}

var number_string = "7, 20, 22, 30–31, 33, 39–40, 46";

var result = convert(number_string);
  
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Используя ESNext, я бы использовал Array.flatMap() вместо jQuery.map(), с String.inclues() для обнаружения тире и Array.from() для генерации подмассива.

const convert = (str) => 
  str.split(', ')
    .flatMap(s => {
      if(!s.includes('–')) return +s;
      
      const [min, max] = s.split('–');
      
      return Array.from({ length: max - min + 1 }, (_, n) => n + +min);
    });

var number_string = "7, 20, 22, 30–31, 33, 39–40, 46";

var result = convert(number_string, '–');
  
console.log(result);
1
ответ дан Ori Drori 26 June 2019 в 22:52
поделиться

Я бы использовал .reduce. Сначала разделите начальную строку запятыми. Если для перебираемой строки нет -, просто введите число в накопитель; в противном случае разделите на -, чтобы получить числа low и high, затем используйте петлю for, чтобы протолкнуть все числа от low до high к аккумулятору:

]
const ToInt = Number;

const numArr = "7, 20, 22, 30–31, 33, 39–40, 46".split(', ');
const result = numArr.reduce((a, str) => {
  if (!str.includes('–')) {
    a.push(ToInt(str));
    return a;
  }
  const [low, high] = str.split('–');
  for (let i = Number(low); i <= high; i++) {
    a.push(i);
  }
  return a;
}, []);
console.log(result);

Если по какой-то причине вы не хотите использовать ES6, вы можете преобразовать его в ES5 с помощью Вавилона :

"use strict";

function _slicedToArray(arr, i) {
  return (
    _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest()
  );
}

function _nonIterableRest() {
  throw new TypeError("Invalid attempt to destructure non-iterable instance");
}

function _iterableToArrayLimit(arr, i) {
  var _arr = [];
  var _n = true;
  var _d = false;
  var _e = undefined;
  try {
    for (
      var _i = arr[Symbol.iterator](), _s;
      !(_n = (_s = _i.next()).done);
      _n = true
    ) {
      _arr.push(_s.value);
      if (i && _arr.length === i) break;
    }
  } catch (err) {
    _d = true;
    _e = err;
  } finally {
    try {
      if (!_n && _i["return"] != null) _i["return"]();
    } finally {
      if (_d) throw _e;
    }
  }
  return _arr;
}

function _arrayWithHoles(arr) {
  if (Array.isArray(arr)) return arr;
}

var ToInt = Number;
var numArr = "7, 20, 22, 30–31, 33, 39–40, 46".split(", ");
var result = numArr.reduce(function(a, str) {
  if (str.indexOf("–") === -1) {
    a.push(ToInt(str));
    return a;
  }

  var _str$split = str.split("–"),
    _str$split2 = _slicedToArray(_str$split, 2),
    low = _str$split2[0],
    high = _str$split2[1];

  for (var i = Number(low); i <= high; i++) {
    a.push(i);
  }

  return a;
}, []);
console.log(result);

(но версия ES6 более краткая и, вероятно, много легче читать и понимать)

1
ответ дан CertainPerformance 26 June 2019 в 22:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: