This question already has answers here:
Find min / max value in Swift Array
(16 answers)
Closed 1 year ago.
I am writing an algorithm to find the lowest number in an array however my print statement keeps saying that the lowest number is 0. I have the following:
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
func findMin(numbers: NSArray) {
var minValue = numbers[0]
var isSmallest: Bool
for i in 0...numbers.count {
isSmallest = true
for j in 0...numbers.count {
if i > j {
isSmallest = false
}
}
if isSmallest {
minValue = i
}
}
print("Smallest value in the list is \(minValue)")
}
findMin(numbers: list as NSArray)
My print statement returns as:
"Smallest value in the list is 0\n"
I feel like the algorithm is correct. Any ideas?
EDIT: Answered my own question
I was iterating over indices and not actual values. Thanks to one of the users in the comments. The correct code should be:
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
func findMin(numbers: NSArray) {
var minValue = numbers[0]
var isSmallest: Bool
for i in list {
isSmallest = true
for j in list {
if i > j {
isSmallest = false
}
}
if isSmallest {
minValue = i
}
}
print("Smallest value in the list is \(minValue)")
}
findMin(numbers: list as NSArray)
Simply
let list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
let minValue = list.min()
For logic use try this
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
var minValue = list[0]
for num in list {
minValue = (num < minValue) ? num : minValue
}
print("Smallest value in the list is \(minValue)")
For direct get min value by property
let list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
let minValue = list.min()
Or you could just use
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
list.min() // returns 2
If you'd like to find the min value without an extra loop, try this:
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
func findMin(numbers: NSArray) {
var minValIdx = 0
var minValue = numbers[0] as! Int
for i in 1..<numbers.count {
if (numbers[i] as! Int) < minValue {
minValue = numbers[i] as! Int
minValIdx = i
}
}
print("Smallest value in the list is \(minValue)")
}
findMin(numbers: list as NSArray)
You can use this code in Swift for manual algorithm:
let list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
var smallest = list[0]
for item in list {
if (item < smallest) {
smallest = item
}
}
print("smallest number is: \(smallest)")
And if you want Swift to do the hard work then use this:
let smallest = list.min()
print("smallest number is: \(smallest)")
here it is your solution
let numbers = [1, 6, 3, 9, 4, 6]
let min = minElement(numbers) // 1
let position = find(array, min)// it will return index
Just to throw a few more options out there, assuming you have to actually show some logic:
func min<T:Comparable>(_ elements:[T]) -> T? {
guard let first = elements[0] else {
return nil
}
return elements.reduce(first, min)
}
print(min(list))
or put it in an extension, this is essentially the definition of Array.min
extension Array where Element : Comparable {
func smallest() -> Element? {
guard let first = self.first else {
return nil
}
// Use 'Swift.min' to get to the global function since Array
// already has a min function
return reduce(first, Swift.min)
}
}
print(list.smallest())
You can use this code:
it is in C#
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
int minVal = list[0];
for (int i = 1; i < list.Length; i++)
{
if (list[i] < minVal)
{
minVal = intArray[i];
}
}
To find the minimum element in the sequence, Swift 3 have an istance method called min():
var list = [5, 4, 3, 5, 2, 50, 8, 10, 300]
let minElem = list.min()
If the sequence has no elements, returns nil.
This method can be used also for a list of floats:
let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
let minHeight = heights.min()
You can find the official document referece here
Related
If I have an array [-23,0,43,7,5,2,4], how to do I split the array [odd][even].
I want 4 elements in the first array and 3 elements in the second array.
I tried to do something like this:
let leftArray = Array(mainArray[0..<mainArray.count/2])
let rightArray = Array(mainArray[mainArray.count/2..<mainArray.count])
I keep on getting [-23,0,43] and [7,5,2,4].
I'd create an extension implementing properties that yield the left and right halves of the array. In this implementation left includes the larger half of the array if the array has an odd number of elements.
extension Array {
var left: ArraySlice<Element> {
prefix(count / 2 + count % 2)
}
var right: ArraySlice<Element> {
suffix(count / 2)
}
}
And its usage would be:
let main = [-23, 0, 43, 7, 5, 2, 4]
let left = main.left
let right = main.right
The result of the above is an ArraySlice for efficiency, but if you want an Array you can just use map.
let main = [-23, 0, 43, 7, 5, 2, 4]
let left = main.left.map { $0 }
let right = main.right.map { $0 }
I think you want to split your array in the middle, and for odd counts, have the first part be the larger one. Use a function like this (intentionally spelled our very explicitly):
func splitArray(_ arr: [Int]) -> ([Int], [Int]) {
let count = arr.count
let half = count.isMultiple(of: 2) ? count / 2 : count / 2 + 1
let left = arr[0..<half]
let right = arr[half..<count]
return (Array(left), Array(right))
}
splitArray([-23,0,43,7,5,2,4]) // ([-23, 0, 43, 7], [5, 2, 4])
splitArray([-23,0,43,7,5,2,4,1]) // ([-23, 0, 43, 7], [5, 2, 4, 1])
This can be simplified and be made generic (i.e., work on all kinds of Collections) like so:
extension Collection {
func splitHalf() -> (SubSequence, SubSequence) {
let count = self.count
let left = self.prefix(count / 2 + count % 2)
let right = self.suffix(count / 2)
return (left, right)
}
}
[-23,0,43,7,5,2,4].splitHalf() // ([-23, 0, 43, 7], [5, 2, 4])
[-23,0,43,7,5,2,4,1].splitHalf() // ([-23, 0, 43, 7], [5, 2, 4, 1])
"12345".splitHalf() // (.0 "123", .1 "45")
"123456".splitHalf() // (.0 "123", .1 "456")
Function for split the array
func getSplitArr(arr:[Int])->Void{
let count = arr.count
let secArrCount = abs(count/2)
var firstArray = [Int]()
for i in 0..<secArrCount{
let value = arr[i]
firstArray.append(value)
}
var secondArray = [Int]()
for i in secArrCount..<count{
let value = arr[i]
secondArray.append(value)
}
print("\(firstArray)")
print("\(secondArray)")
}
Use of Functions
self.getSplitArr(arr: [-23,0,43,7,5,2,4])
Your first question wasn't clear. This should return two arrays one where the first array is even and the second is odd every time.
var array = [-23,0,43,7,5,2,4]
func splitArray(in array : [Int]) -> (firstArray :[Int], secondArray: [Int]) {
let firstArray = array.dropLast(array.count / 2).compactMap { item -> Int in
item
}
let secondArray = array.dropFirst((array.count / 2) + 1).compactMap { item -> Int in
item
}
return (firstArray,secondArray)
}
var newArray = splitArray(in: array)
print(newArray)
I'm working on a function that will help me quickly find all the upper structure triads (3-note chord) that I can add to a 4-note 7th chord to create a larger compound chord, as well of the roots and names of each triad. The example I'm testing right now is a 13#11 chord, which has the following degrees in a 12-note octave (when the root is 0): [0, 2, 4, 6, 7, 9, 10]*
*side note: [0, 4, 6, 7, 9, 10] would also match as a 13#11.
The base 7th chord is a dominant 7th: [0, 4, 7, 9].I already know which triads complete the chord: a major triad on the 9th, [2, 6, 9], and a diminished triad on the #11, 0, 6, 9 (only the 6 (#11th) and 9 (13th) are actually necessary to build a 13#11 chord; the 2 (9th) is optional).
I actually already have a function that will give me these results, I'm just wondering if there's a faster/more efficient way to do it? It just feels a little bulky/clunky right now. Any help would be appreciated.
Thanks!
Jake
extension Int {
func degreeInOctave() -> Int {
switch self {
case 0...11:
return self
case 12...:
return self - 12
default:
return self + 12
}
}
}
var ust: [Int] = [0, 2, 4, 6, 7, 9, 10]
let maj = [0, 4, 7]
let min = [0, 3, 7]
let aug = [0, 4, 8]
let dim = [0, 3, 6]
let sus4 = [0, 5, 7]
let sus2 = [0, 2, 7]
let triadDegs = [maj, min, aug, dim, sus4, sus2]
var triadRoots: [Int] = []
var triadQualities: [String] = []
func findUpperStructureTriads(degs: [Int]) {
let degCount = degs.count
var firstIndex = 0
while firstIndex < (degCount - 2) {
var secondIndex = firstIndex + 1
while secondIndex < (degCount - 1) {
var thirdIndex = secondIndex + 1
while thirdIndex < (degCount) {
var threeNoteGroup = [degs[firstIndex], degs[secondIndex], degs[thirdIndex]]
func checkForTriad(triad: [Int]) -> Bool {
if triadDegs.contains(triad) {
switch triad {
case maj:
triadQualities.append("major")
case min:
triadQualities.append("minor")
case aug:
triadQualities.append("augmented")
case dim:
triadQualities.append("diminished")
case sus4:
triadQualities.append("sus4")
case sus2:
triadQualities.append("sus2")
default:
()
}
return true
} else {
return false
}
}
if threeNoteGroup.contains(6), threeNoteGroup.contains(9){
var inversionCount = 0
var newGroup = threeNoteGroup.map {$0 - threeNoteGroup[0]}
while inversionCount < 3 {
func invert() {
newGroup = newGroup.map {($0 - newGroup[1]).degreeInOctave()}
let newlast = newGroup.remove(at: 0)
newGroup.append(newlast)
}
if checkForTriad(triad: newGroup) {
print(threeNoteGroup, threeNoteGroup[inversionCount])
triadRoots.append(threeNoteGroup[inversionCount])
break
}
invert()
inversionCount += 1
}
}
thirdIndex += 1
}
secondIndex += 1
}
firstIndex += 1
}
for i in 0...(triadRoots.count - 1) {
print(triadRoots[i], triadQualities[i])
}
}
findUpperStructureTriads(degs: ust)
outputs:
[0, 6, 9] 6
[2, 6, 9] 2
6 diminished
2 major
This is the solution I had tried but It was in the order of O(n^2) so didn't passed the test result
func sortArrayByValueAndByFrequency(nums : [Int]) {
var countDict = [Int : Int]()
var count = Int()
var values = Int()
var output = [Int]()
for index in 0 ..< nums.count {
for index2 in 0 ..< nums.count{
if nums[index2] == nums[index] {
values = nums[index2]
count += 1
}
}
countDict[values] = count
count = 0
}
let sortedByKey = countDict.sorted { ($0.key < $1.key)}
let sortedByValue = sortedByKey.sorted { ($0.value < $1.value)}
for (k,v) in sortedByValue {
for _ in 1 ... v {
output.append(k)
}
}
output.forEach { (orderedNumber) in
print(orderedNumber)
}
}
Example input/output:
Example array = [1,1,2,3,4,5,5,6,7,7,7,8,9,9,9,20,25,21,20]
Expected output = [2,3,4,6,8,21,25,1,1,5,5,20,20,7,7,7,9,9,9]
example 2 = [1,2,3,4,4,3,3]
output = [1,2,4,4,3,3,3]
This question was asked to me on HackerRank
First determine the number of occurrences of each value (O(n)),
then sort the values, with the number of occurrences as the
first sort criterion, and the value itself as the second
sort criterion (O(n log(n))). The sorting is conveniently done
with a tuple-comparison (compare Swift - Sort array of objects with multiple criteria):
let array = [1,1,2,3,4,5,5,6,7,7,7,8,9,9,9,20,25,21,20]
let countDict = array.reduce(into: [Int:Int]()) {
$0[$1, default: 0] += 1
}
let sorted = array.sorted(by: {
(countDict[$0]!, $0) < (countDict[$1]!, $1)
})
print(sorted)
// [2, 3, 4, 6, 8, 21, 25, 1, 1, 5, 5, 20, 20, 7, 7, 7, 9, 9, 9]
I am trying to get the largest value in a dictionary of arrays and I need also get the key of that array.
This is how I get the largest value:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25]
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
I would use max method in your dictionary values and get the maximum value from the resulting tuple values:
if let result = interestingNumbers.max(by: {$0.value.max() ?? 0 < $1.value.max() ?? 0}),
let maxValue = result.value.max() {
print(result.key) // "Square\n"
print(result.value) // "[1, 4, 9, 16, 25]\n"
print(maxValue) // 25
}
Why don't you use a tuple to hold the largest value?
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest: (kind: String?, number: Int) = (nil, 0)
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest.number {
largest = (kind, number)
}
}
}
Which can be further simplified to:
var largest: (kind: String?, number: Int) = (nil, 0)
for (kind, numbers) in interestingNumbers {
let max = numbers.max() ?? 0
if max > largest.number {
largest = (kind, max)
}
}
Another method is to flatten the values first into a (kind, number) sequence:
let flattened = interestingNumbers
.map { (kind, numbers) in numbers.map { (kind, $0) } }
.joined()
let largest = flattened.max(by: { $0.1 < $1.1} )
print(largest)
or you can realize that only the maximum value in every array is the most important, therefore :
let largestPerKind = interestingNumbers
.map { (kind, numbers) in (kind, numbers.max() ?? 0) }
let largest = largestPerKind.max(by: { $0.1 < $1.1} )
print(largest)
You can use Swift function's for that.
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
if let value = interestingNumbers.map ({ ($0, $1.max() ?? 0) }).max(by: { $0.1 < $1.1 }) {
print(value.0, value.1) // Square 25
}
Let's go with step by step
First I have created array of tuple with type [(String, Int)], with first place it will store group and on second place it will store max value from its corresponding array.
let array = interestingNumbers.map ({ ($0, $1.max() ?? 0) })
//[("Fibonacci", 8), ("Square", 25), ("Prime", 13)]
Now find the max Int from the array of tuple.
if let value = array.max(by: { $0.1 < $1.1 }) {
print(value.0, value.1) //Will print group here it is "Square 25"
}
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var largest_kind : String? =nil
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largest_kind = kind
}
}
}
Given array of n elements, i.e.
var array = [1, 2, 3, 4, 5]
I can write an extension to the Array so I can modify array to achieve this output: [2, 3, 4, 5, 1]:
mutating func shiftRight() {
append(removeFirst())
}
Is there a way to implement such a function that would shift array by any index, positive or negative. I can implement this function in imperative style with if-else clauses, but what I am looking for is functional implementation.
The algorithm is simple:
Split array into two by the index provided
append first array to the end of the second
Is there any way to implement it in functional style?
The code I've finished with:
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])
}
}
You can use ranged subscripting and concatenate the results. This will give you what you're looking for, with names similar to the standard library:
extension Array {
func shiftRight(var amount: Int = 1) -> [Element] {
guard count > 0 else { return self }
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]
Instead of subscripting, you could also return Array(suffix(count - amount) + prefix(amount)) from shiftRight().
With Swift 5, you can create shift(withDistance:) and shiftInPlace(withDistance:) methods in an Array extension with the following implementation in order to solve your problem:
extension Array {
/**
Returns a new array with the first elements up to specified distance being shifted to the end of the collection. If the distance is negative, returns a new array with the last elements up to the specified absolute distance being shifted to the beginning of the collection.
If the absolute distance exceeds the number of elements in the array, the elements are not shifted.
*/
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])
}
/**
Shifts the first elements up to specified distance to the end of the array. If the distance is negative, shifts the last elements up to the specified absolute distance to the beginning of the array.
If the absolute distance exceeds the number of elements in the array, the elements are not shifted.
*/
mutating func shiftInPlace(withDistance distance: Int = 1) {
self = shift(withDistance: distance)
}
}
Usage:
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: []
I took a stab at writing some extensions for this. It has some nice features:
Shifting by an amount greater than count causes a wrap-around.
Shifting by negative amounts flips the direction
Exposes functions as the bit-shift binary operators (<<, <<=, >>, >>=)
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) }
You can see it in action here.
Here is a more general solution, which implements this functionality lazily for any type that meets the requirements:
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) }
}
Here's a functional implementation for "in place" rotation that doesn't require extra memory nor a temporary variable and performs no more than one swap per element.
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
}
}
}
It optimally supports zero, positive and negative rotations as well as rotations of larger magnitude than the array size and rotation of an empty array (i.e. it cannot fail).
Uses negative values to rotate in the other direction (to the right).
Rotating a 3 element array by 10 is like rotating it by 1, the fist nine rotations will bring it back to its initial state (but we don't want to move elements more than once).
Rotating a 5 element array to the right by 3, i.e. rotateLeft(by:-3) is equivalent to rotateLeft(by:2). The function's "effective offset" takes that into account.
An easy solution,
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 []
}
I know I late to the party, but this answer based on the question works great?
extension Array {
mutating func shiftRight(p: Int) {
for _ in 0..<p {
append(removeFirst())
}
}
}
start [5, 0, 4, 11, 0]
shift [5, 0, 4, 11, 0] shift 0
shift [0, 4, 11, 0, 5] shift 1
shift [4, 11, 0, 5, 0] shift 2
shift [11, 0, 5, 0, 4] shift 3
Even better, if you ask it to shift more elements than there are in the array, it simply keeps circling.
Following the Nate Cook answers , I need also to shift an array returning reverse order, so I made:
//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)
}
}
We have for example:
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]
In objective C you can simply get left shifted array like this:
- (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;
}
The fastest way is (but takes double memory!):
input:
var arr = [1,2,3,4,5]
let k = 1 (num steps to rotate)
let n = arr.count ( a little but faster )
rotation LEFT:
var temp = arr
for i in 0..<n {
arr[(n-i+k)%n] = temp[i]
}
result: [2, 1, 4, 3, 5]
rotation RIGHT:
var temp = arr
for i in 0..<n {
arr[(i+k)%n] = temp[i]
}
result: [4, 1, 2, 3, 5]