Shift Swift Array

Matriz de colors

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

El objective es cambiar la matriz:

  1. Para comenzar con un color diferente.
  2. Para preservar el order circular de los colors.

Ejemplo 1

Si quisiéramos comenzar con el color naranja (el color en el índice 1 en la matriz original), la matriz se vería así:

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

Ejemplo # 2

Si quisiéramos comenzar con el color verde (el color en el índice 3 en la matriz original), la matriz se vería así:

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

Sé que esto puede llegar tarde. Pero la forma más fácil de rotar o cambiar una matriz es

 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 

Puede extender Array para include un método para devolver un set que contenga los elementos de la matriz original girados por un elemento:

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

Para cambiar los elementos de una matriz una vez

 let colorArray:[UIColor] = [ .networkingColor(), .orangeColor(), .yellowColor(), .greenColor(), .blueColor() ] let z = colorArray.rotate(1) // z is [.orangeColor(), .yellowColor(), .greenColor(), .blueColor(), .networkingColor()] 

y dos veces

 let z = colorArray.rotate(2) // z is [.yellowColor(), .greenColor(), .blueColor(), .networkingColor(), .orangeColor()] 

Puedes repetir manejando el índice de inicio.

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

Si quieres comenzar desde el índice 3

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

La solución rápida y clara Swift 3 y 4 se me ocurrió:

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

Explicación:

  1. Las matrices sin elementos y desplazamientos que producen la identidad de la matriz original se devuelven inmediatamente
  2. Para get la cantidad de turno efectiva independientemente de la cantidad pasada con la function, hacemos algún cálculo de module para deshacerse de los turnos que rotarían los elementos en la matriz más de una vez (por ejemplo, en una Matriz con 5 Objetos, un cambio de +7 es lo mismo que un desplazamiento de +2). Dado que siempre queremos cambiar a la derecha, para poder hacerlo con una function simple en lugar de dos, las inputs negativas tienen que ser tratadas (por ejemplo, en una Matriz con 5 Objetos, un desplazamiento de -2 es igual a un turno de +3). Por lo tanto, ajustamos los resultados negativos del cálculo del module por la longitud de la matriz. Por supuesto, esas 3 líneas podrían hacerse en una sola, pero quería hacer esto lo más legible posible.
  3. Ahora preparamos el turno real tomando el índice ( $0 ) del elemento y devolviendo el índice desplazado sumndo el monto calculado en el paso 2. Si el nuevo índice cae fuera de la longitud de la matriz, debe estar envuelto en el frente.
  4. Y finalmente aplicamos toda la preparación a nuestra matriz con algún engaño: enumerated() nos da una matriz de tuplas [(offset: Int, element: Int)] , que es simplemente el índice original de cada elemento y el elemento en sí. A continuación, orderamos esta matriz enumerada por el offset manipulado (también conocido como el índice del elemento) mediante la aplicación de la function del paso 3. Por último, eliminamos la enumeración asignando los elementos orderados nuevamente a una matriz.

Esta extensión funciona con matrices de cualquier tipo. Ejemplos:

 let colorArray = [ UIColor.networking, UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue ] let shiftedColorArray = [ UIColor.green, UIColor.blue, UIColor.networking, 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]