遍历数组并在另一个数组SWIFT 4中对连续数字进行分组的最佳方法?

时间:2018-08-25 17:00:44

标签: arrays swift

我正在尝试找出使用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 :(得分:9)

我的建议是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) }

答案 1 :(得分:4)

虽然根据@vadian使用IndexSet是个好主意,但它仅在您的情况下有效(连续和正整数),使用索引可能不是您的目的。为此,使用类似的对象有点麻烦,但是做得很好。

一种可能的方法是使用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]]

答案 2 :(得分:4)

这对于负整数也适用:

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]]

答案 3 :(得分:0)

对于不熟悉地图和索引集的用户,请检查以下内容:

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(如果是的话),则使用数组切片并将其添加到具有键的字典中,该键由变量“ count”给出。变量previous index保留上一个拆分的结束索引,以便下一个拆分从previousIndex到当前索引开始