Лучший способ перебрать массив и сгруппировать последовательные числа в другой массив SWIFT 4? - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь найти наиболее эффективный способ использования SWIFT 4 для циклического перебора массива чисел, получения диапазона любых последовательных чисел и добавления их в новый массив. Я мог бы сделать стандартные проверки цикла, но я считаю, что я могу использовать фильтр карты? - Может ли кто-нибудь указать мне правильное направление?

Начало:

myNumbersArray:[Int] = [1,2,3,4,10,11,15,20,21,22,23]

Требуется результат:

newNumbersArray = [
   [1,2,3,4],
   [10,11],
   [15],
   [20,21,22,23]
]

Я опубликую свое решение, если выясню ...

Ответы [ 4 ]

0 голосов
/ 11 октября 2018

Для тех, кто не знаком с картой и набором индексов, отметьте это:

var arr = [0,1,2,4,6,7,9]
var previousIndex = 0
var count = 0
var arrayDict : [Int:[Int]] = [:]
for (index,data) in arr.enumerated() {
  if index == (arr.count - 1) {
     arrayDict[count] = Array(arr[previousIndex ..< index + 1])
     break
  }
  if arr[index + 1] - data != 1 {
    arrayDict[count] = Array(arr[previousIndex ..< index + 1])
    previousIndex = index + 1
    count += 1
  }
}
print(arrayDict)

Логика в том, что я перебираю элементы данного массива и каждый раз проверяю, является ли значение этого индексане меньше, чем значение по индексу + 1 на 1, если это так, я разделяю массив с помощью массива Array и добавляю его в словарь, имеющий ключ, который задается переменной 'count'.переменная previous Index содержит индекс конца предыдущего разбиения, так что следующее разделение начинается с предыдущего индекса до текущего индекса

0 голосов
/ 25 августа 2018

Хотя использование IndexSet в соответствии с @ vadian является хорошей идеей, оно работает только в вашем случае (последовательные и положительные целые числа) и может не являться вашей целью использовать индексы.Немного глупо использовать подобный вид объектов для этого, но хорошо справляется со своей задачей.

Возможный способ - использовать reduce():

let reduced = myNumbersArray.reduce([[Int]]()) { (current, next) -> [[Int]] in
    var result = current
    //Retrieve the last sequence, check if the current - last item of sequence is 1 to know if they are consecutive or not
    if var lastSequence = result.last, let last = lastSequence.last, next-last == 1 {
        lastSequence.append(next)
        result[result.endIndex-1] = lastSequence
        return result
    } else { //It's not => New array of its own
        result.append([next])
        return result
    }
}
print("reduced: \(reduced)")

Вывод:

$>reduced: [[1, 2, 3, 4], [10, 11], [15], [20, 21, 22, 23]]

В соответствии с предложением @ Leo Dabus , с reduce(into:):

let reducedInto = myNumbersArray.reduce(into: [[Int]]()) { (result, next) in
    //Retrieve the last sequence, check if the current - last item of sequence is 1
    if var lastSequence = result.last, let last = lastSequence.last, next-last == 1 {
        lastSequence.append(next)
        result[result.endIndex-1] = lastSequence
    } else { //It's not => New array of its own
        result.append([next])
    }
}
print("reducedInto: \(reducedInto)")

Выход:

$>reducedInto: [[1, 2, 3, 4], [10, 11], [15], [20, 21, 22, 23]]
0 голосов
/ 25 августа 2018

Это также будет работать с отрицательными целыми числами:

extension BidirectionalCollection where Element: BinaryInteger, Index == Int {
    var consecutivelyGrouped: [[Element]] { 
        return reduce(into: []) {
            $0.last?.last?.advanced(by: 1) == $1 ? 
            $0[index(before: $0.endIndex)].append($1) :
            $0.append([$1]) 
        }
    }
}

let numbers = [-5,-4,-2,0,1,3,4,10,11,15,20,21,22,23]
let grouped = numbers.consecutivelyGrouped  // [[-5, -4], [-2], [0, 1], [3, 4], [10, 11], [15], [20, 21, 22, 23]]
0 голосов
/ 25 августа 2018

Мое предложение - IndexSet, где последовательные элементы хранятся в виде диапазонов.

  • Создать набор индексов из массива.
  • Получите rangeView.
  • Отобразить диапазоны в массивы.

let myNumbersArray = [1,2,3,4,10,11,15,20,21,22,23]
let indexSet = IndexSet(myNumbersArray)
let rangeView = indexSet.rangeView
let newNumbersArray = rangeView.map { Array($0.indices) }
...