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]
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 want to find all the unique pairs whose sum will be equal to a given sum. I implement a solution but it returns only the first pair that it finds.
func checkPairs(in numbers: [Int], forSum target: Int) -> String {
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
return ("There is a pair that sums \(target): \(x)+\(y)=\(target)")
}
}
}
return "no pair"
}
print (checkPairs(in: [1, 2, 4, 4, 7, 5, 3], forSum: 8))
Output:
There is a pair that sums 8: 1+7=8
You exit the function early by calling return when the first pair is found. Instead, you should return an array of tuples containing the pairs, iterate over all pairs and add the ones satisfying the requirements to the return array.
func checkPairs(in numbers: [Int], forSum target: Int) -> [(Int,Int)] {
var pairs = [(Int,Int)]()
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
pairs.append((x,y))
}
}
}
return pairs
}
print(checkPairs(in: [1, 2, 4, 4, 7, 5, 3], forSum: 8))
Output:
[(1, 7), (4, 4), (5, 3)]
If you're looking for unique pairs, you can define a custom type holding the pair of numbers and return a Set instead of an Array (the custom type is needed, since you cannot make a Tuple conform to Hashable, which is needed to be able to add elements to a Set).
struct Pair: Hashable {
let smaller:Int
let bigger:Int
init(_ a:Int, _ b:Int) {
if a < b {
smaller = a
bigger = b
} else {
smaller = b
bigger = a
}
}
}
extension Pair: CustomStringConvertible {
var description:String {
return "\((smaller,bigger))"
}
}
func checkPairs(in numbers: [Int], forSum target: Int) -> Set<Pair> {
var pairs = Set<Pair>()
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
pairs.insert(Pair(x,y))
}
}
}
return pairs
}
print(checkPairs(in: [1, 2, 4, 4, 7, 5, 3], forSum: 8))
print(checkPairs(in: [1, 2, 4, 4, 7, 5, 3, 4, 1], forSum: 8))
Output:
[(4, 4), (3, 5), (1, 7)]
[(4, 4), (3, 5), (1, 7)]
here is one of options you can do
let array = [1, 2, 4, 4, 7, 5, 3]
let target = 8
func checkPairs(in numbers: [Int], forSum target: Int) -> String {
var pairs = ""
for (i, x) in numbers.enumerated() {
for y in numbers[i+1 ..< numbers.count] {
if x + y == target {
pairs += ("There is a pair that sums \(target): \(x)+\(y)=\(target)\n")
}
}
}
return pairs
}
print(checkPairs(in: array, forSum: target))
output will be There is a pair that sums 8: 1+7=8 There is a pair
that sums 8: 4+4=8 There is a pair that sums 8: 5+3=8
I am trying to write an extension for Array Types that sums the n-previous indexes in the index n.
let myArray = [1, 2, 3, 4, 5]
let mySumArray = myArray.sumNIndex()
print(mySumArray)
// returns [1,3,6,10,15]
I have tried various approaches which all failed at some point.
For instance, the example hereafter triggers a compile error
"Cannot invoke 'reduce' with an argument list of type '(Int, _)'":
extension Array {
mutating func indexSum() {
var tempArray = [Any]()
for index in 1...self.count - 1 {
self[index] += self[.prefix(index + 2).reduce(0, +)]
}
}
}
This other attempt triggers another compile error:
"Binary operator '+=' cannot be applied to two 'Element' operands"
extension Array {
mutating func indexSum() {
var tempArray = [Any]()
for index in 1...self.count - 1 {
self[index] += self[index - 1]
}
}
}
Any idea is welcome!
Thank you very much for your help!
EDIT: Many thanks to #Martin and #Carpsen who figured it out in 2 different ways
#Martin using map method:
extension Array where Element: Numeric {
func cumulativeSum() -> [Element] {
var currentSum: Element = 0
return map {
currentSum += $0
return currentSum
}
}
}
#Carpsen using reduce method:
extension Array where Element: Numeric {
func indexSum() -> [Element] {
return self.reduce(into: [Element]()) {(acc, element) in
return acc + [(acc.last ?? 0) + element]
})
}
}
The main problem is that the addition operator + is not defined for elements
of arbitrary arrays. You need to restrict the extension method, e.g. to
arrays of Numeric elements.
Also there is no need to use Any.
Here is a possible implementation as a non-mutating method:
extension Array where Element: Numeric {
func cumulativeSum() -> [Element] {
var currentSum: Element = 0
return map {
currentSum += $0
return currentSum
}
}
}
Examples:
let intArray = [1, 2, 3, 4, 5]
print(intArray.cumulativeSum()) // [1, 3, 6, 10, 15]
let floatArray = [1.0, 2.5, 3.25]
print(floatArray.cumulativeSum()) [1.0, 3.5, 6.75]
In a similar fashion we can “cumulatively join” the elements of a
string array. enumerated() is now used to provide the current element
index together with the element, and that is used to decide whether to
insert the separator or not:
extension Array where Element == String {
func cumulativeJoin(separator: String) -> [Element] {
var currentJoin = ""
return enumerated().map { (offset, elem) in
if offset > 0 { currentJoin.append(separator) }
currentJoin.append(elem)
return currentJoin
}
}
}
Examples:
let stringArray = ["a", "b", "c"]
print(stringArray.cumulativeJoin()) // ["a", "ab", "abc"]
print(stringArray.cumulativeJoin(separator: ":")) // ["a", "a:b", "a:b:c"]
Try this:
let myArray = [1, 2, 3, 4, 5]
myArray.reduce([Int](), {accumulator, element in
return accumulator + [(accumulator.last ?? 0) + element]
})
//[1, 3, 6, 10, 15]
What this reduce does is:
Start with an empty array
With each element from myArray it calculates its sum with the last element in the accumulator
Return the previous array plus the last sum
Here is a simpler, but longer version:
let myArray = [1, 2, 3, 4, 5]
let newArray = myArray.reduce([Int](), {accumulator, element in
var tempo = accumulator
let lastElementFromTheAccumulator = accumulator.last ?? 0
let currentSum = element + lastElementFromTheAccumulator
tempo.append(currentSum)
return tempo
})
print(newArray) //[1, 3, 6, 10, 15]
A more efficient solution, as suggested by Martin R in the comments, uses reduce(into:):
myArray.reduce(into: [Int]()) { (accumulator, element) in
accumulator += [(accumulator.last ?? 0) + element]
}
//[1, 3, 6, 10, 15]
And you could have it as an extension:
extension Array where Element: Numeric {
func indexSum() -> [Element] {
return self.reduce([Element](), {acc, element in
return acc + [(acc.last ?? 0) + element]
})
}
}
myArray.indexSum() //[1, 3, 6, 10, 15]
Here a solution that will work with strings too:
extension Array where Element == String {
func indexSum() -> [String] {
return self.reduce(into: [String]()) {(accumulator, element) in
accumulator += [(accumulator.last ?? "") + element]
}
}
}
["a", "b", "c", "d"].indexSum() //["a", "ab", "abc", "abcd"]
If you'd like to have a separator between the elements of the initial array elements, you could use this extension:
extension Array where Element == String {
func indexSum(withSparator: String) -> [String] {
return self.reduce(into: [String]()) {(accumulator, element) in
var previousString = ""
if let last = accumulator.last {
previousString = last + " "
}
accumulator += [previousString + element]
}
}
}
["a", "b", "c", "d"].indexSum(withSparator: " ") //["a", "a b", "a b c", "a b c d"]
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]
I have an Array of numbers and I want to know which number is most frequent in this array. The array sometimes has 5-6 integers, sometimes it has 10-12, sometimes even more - also the integers in the array can be different. So I need a function which can work with different lengths and values of an array.
One example:
myArray = [0, 0, 0, 1, 1]
Another example:
myArray = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
Now I am searching for a function which gives out 0 (in the first example) as Integer, as it is 3 times in this array and the other integer in the array (1) is only 2 times in the array. Or for the second example it would be 4.
It seems pretty simple, but I cannot find a solution for this. Found some examples in the web, where the solution is to work with dictionaries or where the solution is simple - but I cannot use it with Swift 3 it seems...
However, I did not find a solution which works for me. Someone has an idea how to get the most frequent integer in an array of integers?
You can also use the NSCountedSet, here's the code
let nums = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
let countedSet = NSCountedSet(array: nums)
let mostFrequent = countedSet.max { countedSet.count(for: $0) < countedSet.count(for: $1) }
Thanks to #Ben Morrow for the smart suggestions in the comments below.
let myArray = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
// Create dictionary to map value to count
var counts = [Int: Int]()
// Count the values with using forEach
myArray.forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
// Find the most frequent value and its count with max(by:)
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
print("\(value) occurs \(count) times")
}
Output:
4 occurs 4 times
Here it is as a function:
func mostFrequent(array: [Int]) -> (value: Int, count: Int)? {
var counts = [Int: Int]()
array.forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
return (value, count)
}
// array was empty
return nil
}
if let result = mostFrequent(array: [1, 3, 2, 1, 1, 4, 5]) {
print("\(result.value) occurs \(result.count) times")
}
1 occurs 3 times
Update for Swift 4:
Swift 4 introduces reduce(into:_:) and default values for array look ups which enable you to generate the frequencies in one efficient line. And we might as well make it generic and have it work for any type that is Hashable:
func mostFrequent<T: Hashable>(array: [T]) -> (value: T, count: Int)? {
let counts = array.reduce(into: [:]) { $0[$1, default: 0] += 1 }
if let (value, count) = counts.max(by: { $0.1 < $1.1 }) {
return (value, count)
}
// array was empty
return nil
}
if let result = mostFrequent(array: ["a", "b", "a", "c", "a", "b"]) {
print("\(result.value) occurs \(result.count) times")
}
a occurs 3 times
The most frequent value is called the "mode". Here's a concise version:
let mode = myArray.reduce([Int: Int]()) {
var counts = $0
counts[$1] = ($0[$1] ?? 0) + 1
return counts
}.max { $0.1 < $1.1 }?.0
Whether that's considered "unreadable" or "elegant" depends on your feelings towards higher order functions. Nonetheless, here it is as a generic method in an extension on Array (so it'll work with any Hashable element type):
extension Array where Element: Hashable {
var mode: Element? {
return self.reduce([Element: Int]()) {
var counts = $0
counts[$1] = ($0[$1] ?? 0) + 1
return counts
}.max { $0.1 < $1.1 }?.0
}
}
Simply remove the .0 if you'd rather have a tuple that includes the count of the mode.
My take on it with Swift 5:
extension Collection {
/**
Returns the most frequent element in the collection.
*/
func mostFrequent() -> Self.Element?
where Self.Element: Hashable {
let counts = self.reduce(into: [:]) {
return $0[$1, default: 0] += 1
}
return counts.max(by: { $0.1 < $1.1 })?.key
}
}
I have tried the following code. It helps especially when the max count is applicable for 2 or more values.
var dictionary = arr.reduce(into: [:]) { counts, number in counts[number, default: 0] += 1}
var max = dictionary.values.max()!
dictionary = dictionary.filter{$0.1 == max}
mode = dictionary.keys.min()!
func mostR(num : [Int]) -> (number : Int , totalRepeated : Int)
{
var numberTofind : Int = 0
var total : Int = 0
var dic : [Int : Int] = [:]
for index in num
{
if let count = dic[index]
{
dic[index] = count + 1
}
else
{
dic[index] = 1
}
}
var high = dic.values.max()
for (index , count) in dic
{
if dic[index] == high
{
numberTofind = index
top.append(count)
total = count
}
}
return (numberTofind , total)
}
var array = [1,22,33,55,4,3,2,0,0,0,0]
var result = mostR(num : [1,22,3,2,43,2,11,0,0,0])
print("the number is (result.number) and its repeated by :(result.totalRepeated)" )
Here is an encapsulated/reusable method.
extension Array where Element: Hashable {
/// The mode will be nil when the array is empty.
var mode: Element? {
var counts: [Element: Int] = [:]
forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
print("\(value) occurs \(count) times")
return value
} else {
return nil
}
}
}
usage:
print([3, 4, 5, 6, 6].mode) // 6
Keep track of each occurrence, counting the value of each key in a dictionary. This case is exclusive for integers. Will update this method using generics.
func mostCommon(of arr: [Int]) -> Int {
var dict = [Int:Int]()
arr.forEach {
if let count = dict[$0] {
dict[$0] = count + 1
} else {
dict[$0] = 1
}
}
let max = dict.values.max()
for (_ , value) in dict {
if value == max {
return value
}
}
return -1
}