给出n个元素的数组,即
var array = [1, 2, 3, 4, 5]
我可以编写Array
的扩展名,以便我可以修改数组来实现此输出:[2, 3, 4, 5, 1]
:
mutating func shiftRight() {
append(removeFirst())
}
有没有办法实现这样一个函数,可以通过任何索引(正或负)移动数组。我可以使用if-else
子句以命令式样式实现此函数,但我正在寻找的是功能实现。
算法很简单:
有没有办法以功能样式实现它?
我完成的代码:
extension Array {
mutating func shift(var amount: Int) {
guard -count...count ~= amount else { return }
if amount < 0 { amount += count }
self = Array(self[amount ..< count] + self[0 ..< amount])
}
}
答案 0 :(得分:22)
您可以使用远程订阅并连接结果。这将为您提供所需的信息,其名称与标准库类似:
extension Array {
func shiftRight(var amount: Int = 1) -> [Element] {
assert(-count...count ~= amount, "Shift amount out of bounds")
if amount < 0 { amount += count } // this needs to be >= 0
return Array(self[amount ..< count] + self[0 ..< amount])
}
mutating func shiftRightInPlace(amount: Int = 1) {
self = shiftRight(amount)
}
}
Array(1...10).shiftRight()
// [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
Array(1...10).shiftRight(7)
// [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]
您也可以从Array(suffix(count - amount) + prefix(amount))
返回shiftRight()
。
答案 1 :(得分:15)
使用Swift 5,您可以使用以下实现在shift(withDistance:)
扩展名中创建shiftInPlace(withDistance:)
和Array
方法,以解决您的问题:
extension Array {
func shift(withDistance distance: Int = 1) -> Array<Element> {
let offsetIndex = distance >= 0 ?
self.index(startIndex, offsetBy: distance, limitedBy: endIndex) :
self.index(endIndex, offsetBy: distance, limitedBy: startIndex)
guard let index = offsetIndex else { return self }
return Array(self[index ..< endIndex] + self[startIndex ..< index])
}
mutating func shiftInPlace(withDistance distance: Int = 1) {
self = shift(withDistance: distance)
}
}
用法:
let array = Array(1...10)
let newArray = array.shift(withDistance: 3)
print(newArray) // prints: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
var array = Array(1...10)
array.shiftInPlace(withDistance: -2)
print(array) // prints: [9, 10, 1, 2, 3, 4, 5, 6, 7, 8]
let array = Array(1...10)
let newArray = array.shift(withDistance: 30)
print(newArray) // prints: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let array = Array(1...10)
let newArray = array.shift(withDistance: 0)
print(newArray) // prints: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var array = Array(1...10)
array.shiftInPlace()
print(array) // prints: [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
var array = [Int]()
array.shiftInPlace(withDistance: -2)
print(array) // prints: []
答案 2 :(得分:2)
我为此写了一些扩展。它有一些很好的功能:
count
的数量会导致环绕。<<
,<<=
,>>
,>>=
)
extension Array {
public func shiftedLeft(by rawOffset: Int = 1) -> Array {
let clampedAmount = rawOffset % count
let offset = clampedAmount < 0 ? count + clampedAmount : clampedAmount
return Array(self[offset ..< count] + self[0 ..< offset])
}
public func shiftedRight(by rawOffset: Int = 1) -> Array {
return self.shiftedLeft(by: -rawOffset)
}
public mutating func shiftLeftInPlace(by rawOffset: Int = 1) {
if rawOffset == 0 { return /* no-op */ }
func shiftedIndex(for index: Int) -> Int {
let candidateIndex = (index + rawOffset) % self.count
if candidateIndex < 0 {
return candidateIndex + self.count
}
return candidateIndex
}
// Create a sequence of indexs of items that need to be swapped.
//
// For example, to shift ["A", "B", "C", "D", "E"] left by 1:
// Swapping 2 with 0: ["C", "B", "A", "D", "E"]
// Swapping 4 with 2: ["C", "B", "E", "D", "A"]
// Swapping 1 with 4: ["C", "A", "E", "D", "B"]
// Swapping 3 with 1: ["C", "D", "E", "A", "B"] <- Final Result
//
// The sequence here is [0, 2, 4, 1, 3].
// It's turned into [(2, 0), (4, 2), (1, 4), (3, 1)] by the zip/dropFirst trick below.
let indexes = sequence(first: 0, next: { index in
let nextIndex = shiftedIndex(for: index)
if nextIndex == 0 { return nil } // We've come full-circle
return nextIndex
})
print(self)
for (source, dest) in zip(indexes.dropFirst(), indexes) {
self.swapAt(source, dest)
print("Swapping \(source) with \(dest): \(self)")
}
print(Array<(Int, Int)>(zip(indexes.dropFirst(), indexes)))
}
public mutating func shiftRightInPlace(by rawOffset: Int = 1) {
self.shiftLeftInPlace(by: rawOffset)
}
}
public func << <T>(array: [T], offset: Int) -> [T] { return array.shiftedLeft(by: offset) }
public func >> <T>(array: [T], offset: Int) -> [T] { return array.shiftedRight(by: offset) }
public func <<= <T>(array: inout [T], offset: Int) { return array.shiftLeftInPlace(by: offset) }
public func >>= <T>(array: inout [T], offset: Int) { return array.shiftRightInPlace(by: offset) }
您可以在行动here中看到它。
这是一个更通用的解决方案,它可以为任何满足要求的类型延迟实现此功能:
extension RandomAccessCollection where
Self: RangeReplaceableCollection,
Self.Index == Int,
Self.IndexDistance == Int {
func shiftedLeft(by rawOffset: Int = 1) -> RangeReplaceableSlice<Self> {
let clampedAmount = rawOffset % count
let offset = clampedAmount < 0 ? count + clampedAmount : clampedAmount
return self[offset ..< count] + self[0 ..< offset]
}
func shiftedRight(by rawOffset: Int = 1) -> RangeReplaceableSlice<Self> {
return self.shiftedLeft(by: -rawOffset)
}
mutating func shiftLeft(by rawOffset: Int = 1) {
self = Self.init(self.shiftedLeft(by: rawOffset))
}
mutating func shiftRight(by rawOffset: Int = 1) {
self = Self.init(self.shiftedRight(by: rawOffset))
}
//Swift 3
static func << (c: Self, offset: Int) -> RangeReplaceableSlice<Self> { return c.shiftedLeft(by: offset) }
static func >> (c: Self, offset: Int) -> RangeReplaceableSlice<Self> { return c.shiftedRight(by: offset) }
static func <<= (c: inout Self, offset: Int) { return c.shiftLeft(by: offset) }
static func >>= (c: inout Self, offset: Int) { return c.shiftRight(by: offset) }
}
答案 3 :(得分:1)
这是“就地”轮换的功能实现,不需要额外的内存或临时变量,每个元素执行不超过一次交换。
extension Array
{
mutating func rotateLeft(by rotations:Int)
{
let _ = // silence warnings
(1..<Swift.max(1,count*((rotations+1)%(count+1)%1))) // will do zero or count - 1 swaps
.reduce((i:0,r:count+rotations%count)) // i: swap index r:effective offset
{ s,_ in let j = (s.i+s.r)%count // j: index of value for position i
swap(&self[j],&self[s.i]) // swap to place value at rotated index
return (j,s.r) // continue with next index to place
}
}
}
它最佳地支持零,正和负旋转以及比阵列大小和空阵列的旋转更大幅度的旋转(即,它不会失败)。
使用负值向另一个方向(向右)旋转。
将3个元素数组旋转10就像将其旋转1一样,第9次旋转将使其恢复到初始状态(但我们不想多次移动元素)。
将5个元素数组向右旋转3,即rotateLeft(by:-3)等效于rotateLeft(by:2)。函数的“有效偏移量”将此考虑在内。
答案 4 :(得分:1)
一个简单的解决方案,
public func solution(_ A : [Int], _ K : Int) -> [Int] {
if A.count > 0 {
let roundedK: Int = K % A.count
let rotatedArray = Array(A.dropFirst(A.count - roundedK) + A.dropLast(roundedK))
return rotatedArray
}
return []
}
答案 5 :(得分:0)
在Nate Cook answers之后,我还需要移动一个返回相反顺序的数组,所以我做了:
//MARK: - Array extension
Array {
func shiftRight( amount: Int = 1) -> [Element] {
var amountMutable = amount
assert(-count...count ~= amountMutable, "Shift amount out of bounds")
if amountMutable < 0 { amountMutable += count } // this needs to be >= 0
return Array(self[amountMutable ..< count] + self[0 ..< amountMutable])
}
func reverseShift( amount: Int = 1) -> [Element] {
var amountMutable = amount
amountMutable = count-amountMutable-1
let a: [Element] = self.reverse()
return a.shiftRight(amountMutable)
}
mutating func shiftRightInPlace(amount: Int = 1) {
self = shiftRight(amount)
}
mutating func reverseShiftInPlace(amount: Int = 1) {
self = reverseShift(amount)
}
}
我们有例如:
Array(1...10).shiftRight()
// [2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
Array(1...10).shiftRight(7)
// [8, 9, 10, 1, 2, 3, 4, 5, 6, 7]
Array(1...10).reverseShift()
// [2, 1, 10, 9, 8, 7, 6, 5, 4, 3]
Array(1...10).reverseShift(7)
// [8, 7, 6, 5, 4, 3, 2, 1, 10, 9]
答案 6 :(得分:-1)
在目标C中你可以像这样简单地得到左移阵列:
- (NSMutableArray *)shiftedArrayWithOffset:(NSInteger)offset
{
NSMutableArray *bufferArray = [[NSMutableArray alloc] initWithArray:originalArray];
for (int i = 0; i < offset; i++)
{
id object = [bufferArray firstObject];
[bufferArray removeObjectAtIndex:0];
[bufferArray addObject:object];
}
return bufferArray;
}
答案 7 :(得分:-2)
最快的方式是(但需要双倍内存!):
输入:
var arr = [1,2,3,4,5]
let k = 1 (num steps to rotate)
let n = arr.count ( a little but faster )
轮换 LEFT :
var temp = arr
for i in 0..<n {
arr[(n-i+k)%n] = temp[i]
}
result: [2, 1, 4, 3, 5]
轮换右:
var temp = arr
for i in 0..<n {
arr[(i+k)%n] = temp[i]
}
result: [4, 1, 2, 3, 5]