【问题标题】:Shift Swift Array移位 Swift 数组
【发布时间】:2015-07-22 05:38:32
【问题描述】:

颜色数组

let colorArray = [
    UIColor.redColor(),
    UIColor.orangeColor(),
    UIColor.yellowColor(),
    UIColor.greenColor(),
    UIColor.blueColor()
]

目标是移位数组:

  1. 从不同的颜色开始。
  2. 保持颜色的循环顺序。

示例 #1

如果我们想从 橙色(原始数组中索引 1 处的颜色)开始,数组将如下所示:

let colorArray = [
    UIColor.orangeColor(),
    UIColor.yellowColor(),
    UIColor.greenColor(),
    UIColor.blueColor(),
    UIColor.redColor(),
]

示例 #2

如果我们想从 绿色(原始数组中索引 3 处的颜色)开始,数组将如下所示:

let colorArray = [
    UIColor.greenColor(),
    UIColor.blueColor(),
    UIColor.redColor(),
    UIColor.orangeColor(),
    UIColor.yellowColor()
]

【问题讨论】:

  • 只删除要开始的颜色之前的颜色,然后将它们附加到数组的末尾?

标签: ios arrays swift


【解决方案1】:

我知道这可能会迟到。但是旋转或移动数组最简单的方法是

func shifter(shiftIndex: Int) {
   let strArr: [String] = ["a","b","c","d"]
   var newArr = strArr[shiftIndex..<strArr.count]
   newArr += strArr[0..<shiftIndex]       
   println(newArr)  }

shifter(2) //[c, d, a, b] you can modify the function to take array as input

【讨论】:

  • 出现错误:无法使用 'CountableRange' 类型的索引来下标 '[CGColor]' 类型的值 我的代码是:```guard let indexOfStartColor = possibleColors.index(of: startColor) else { return } let index = indexOfStartColor.distance(to: 0) rotateColors = possibleColors[index..
  • 不以负索引移动,即相反!
【解决方案2】:

我想出的短而清晰的 Swift 3 & 4 解决方案:

extension Array {

    func shifted(by shiftAmount: Int) -> Array<Element> {

        // 1
        guard self.count > 0, (shiftAmount % self.count) != 0 else { return self }

        // 2
        let moduloShiftAmount = shiftAmount % self.count
        let negativeShift = shiftAmount < 0
        let effectiveShiftAmount = negativeShift ? moduloShiftAmount + self.count : moduloShiftAmount

        // 3
        let shift: (Int) -> Int = { return $0 + effectiveShiftAmount >= self.count ? $0 + effectiveShiftAmount - self.count : $0 + effectiveShiftAmount }

        // 4
        return self.enumerated().sorted(by: { shift($0.offset) < shift($1.offset) }).map { $0.element }

    }

}

解释:

  1. 没有元素的数组和产生 原始数组立即返回
  2. 为了获得有效的移位量,而不管函数传递的量是多少,我们进行一些模计算以消除会多次旋转数组中的元素的移位(例如,在具有 5 个对象的数组中,移位+7 的移位与 +2 的移位相同)。由于我们总是想向右移动,为了用一个简单的函数而不是两个来完成,必须处理负输入(例如,在一个有 5 个对象的数组中,-2 的移位与移位相同+3)。因此我们通过数组的长度来调整模计算的负结果。 当然,这 3 行可以合二为一,但我想让它尽可能可读。
  3. 现在我们通过获取元素的索引 ($0) 并通过添加在步骤 2 中计算的数量返回移位的索引来准备实际移位。如果新索引落在数组长度之外,则需要对其进行包装绕到前面。
  4. 最后,我们通过一些技巧将所有准备工作应用于我们的数组:enumerated() 为我们提供了一个元组数组[(offset: Int, element: Int)],它只是每个元素的原始索引和元素本身。然后,我们通过应用第 3 步中的函数,通过操纵的offset(也就是元素的索引)对这个枚举数组进行排序。最后,我们通过将排序后的元素映射回数组来摆脱枚举。

此扩展适用于任何类型的数组。例子:

let colorArray = [
    UIColor.red,
    UIColor.orange,
    UIColor.yellow,
    UIColor.green,
    UIColor.blue
]

let shiftedColorArray = [
    UIColor.green,
    UIColor.blue,
    UIColor.red,
    UIColor.orange,
    UIColor.yellow
]

colorArray.shifted(by: 2) == shiftedColorArray // returns true

[1,2,3,4,5,6,7].shifted(by: -23) // returns [3,4,5,6,7,1,2]

【讨论】:

【解决方案3】:

您可以扩展Array 以包含一种方法来返回一个数组,该数组包含由一个元素旋转的原始数组的元素:

extension Array {
    func rotate(shift:Int) -> Array {
        var array = Array()
        if (self.count > 0) {
            array = self
            if (shift > 0) {
                for i in 1...shift {
                    array.append(array.removeAtIndex(0))
                }
            }
            else if (shift < 0) {
                for i in 1...abs(shift) {
                    array.insert(array.removeAtIndex(array.count-1),atIndex:0)
                }
            }
        }
        return array
    }
}

将数组的元素移动一次

let colorArray:[UIColor] = [
    .redColor(),
    .orangeColor(),
    .yellowColor(),
    .greenColor(),
    .blueColor()
]

let z = colorArray.rotate(1)

// z is [.orangeColor(), .yellowColor(), .greenColor(), .blueColor(), .redColor()]

两次

let z = colorArray.rotate(2)

// z is [.yellowColor(), .greenColor(), .blueColor(), .redColor(), .orangeColor()]

【讨论】:

  • 这会因空数组而崩溃
【解决方案4】:

您可以通过处理起始索引进行迭代。

func iterate<T>(array:Array<T>, start:Int, callback:(T) -> ()) {
    let count = array.count
    for index in start..<(start + count) {
        callback(array[index % count])
    }
}

如果你想从索引 3 开始

iterate(colors, 3, { (color) -> () in println("color - \(color)")})

【讨论】:

    【解决方案5】:

    @zizutg 答案的变体,可以双向(正面和负面)转变

    extension Array {
        public func shifted(by index: Int) -> Array {
            let adjustedIndex = index %% self.count
    
            return Array(self[adjustedIndex..<self.count] + self[0..<adjustedIndex])
        }
    }
    
    // True modulo function https://stackoverflow.com/a/41180619/683763
    infix operator %%
    public func %%(_ dividend: Int, _ divisor: Int) -> Int {
        precondition(divisor > 0, "modulus must be positive")
        let reminder = dividend % divisor
        return reminder >= 0 ? reminder : reminder + divisor
    }
    

    【讨论】:

      猜你喜欢
      • 2014-10-25
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 2010-11-19
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      • 2021-09-09
      相关资源
      最近更新 更多