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)
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]
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
}
I wrote a really simple bubble sort for a card game. It takes an array of "Card" objects, each of which has a an "order" attribute which indicates the value to be sorted against for the game in question.
The following code stopped compiling some time between Swift Beta 1 and Beta 6, and I'm not exactly sure why.
///Sort the cards array by order
func sortCards(cards: Array<Card>) -> Array<Card> {
var sorted = false
while sorted == false {
sorted = true
for i in 0...cards.count - 2 {
if cards[i].order > cards[i+1].order {
sorted = false
var first = cards[i]
var second = cards[i + 1]
cards[i] = second //ERROR
cards[i + 1] = first //ERROR
}
}
}
return cards
}
The lines where the swap occurs bombs out with a very cryptic message:
#!value $T5 is not identical to 'Card'
What changed, and what am I doing wrong here?
Bonus question: How am I supposed to understand the error message?
Function parameters are by default constant (as if declared with let).
If you want to modify the parameter inside your function, you have to declare it as a variable:
func sortCards(var cards: Array<Card>) -> Array<Card> { ...
Note that only the local parameter cards is modified, not the array passed as
an argument to the function (which seems to be your intention because the function
returns a new array).
I played with the following using swift 3. Hope it'll help some people who come here.
bubble sort:
func bubble(arr: inout [Int]) {
for i in (1..<arr.count).reversed() {
for j in 0..<i where arr[j] > arr[j + 1] {
swap(&arr[j], &arr[j + 1])
}
}
}
using stride:
func bubbleStride(arr: inout [Int]) {
for i in stride(from: arr.count - 1, to: 1, by: -1) {
for j in 0..<i where arr[j] > arr[j + 1] {
swap(&arr[j], &arr[j + 1])
}
}
}
using while:
func bubbleWhile(arr: inout [Int]) {
var i = arr.count - 1
while(i > 0) {
var j = 0
while(j < i) {
if arr[j] > arr[j + 1] {
swap(&arr[j], &arr[j + 1])
}
j += 1
}
i -= 1
}
}
This can be used to generate a random array of integers:
import Cocoa
func ints(cnt: Int, ceiling: Int) -> [Int] {
let arr = Array(repeating: 0, count: cnt)
return arr.map { _ in Int(arc4random_uniform(UInt32(ceiling))) }
}
E.g.:
let a = ints(cnt: 10, ceiling: 100)
print(a)
var b = a
bubble(arr: &b)
print(b)
output:
[13, 30, 68, 19, 1, 4, 28, 65, 96, 13]
[1, 4, 13, 13, 19, 28, 30, 65, 68, 96]
If you declare the function like this, then the array is inmutable. You need to use the keyword inoutlike this:
func sortCards(inout cards: Array<Card>) -> Array<Card> {
//code
}
Then you call it with &:
sortCards(&myArray)
Explanation
The whole model of Arrays and pass by value/reference has changed during the beta process.
In beta 1 arrays passed into subroutines were only kind of passed by value. Arrays passed by value (and let arrays) were still modifiable as long as you didn't change the length of the array, thus breaking the pass-by-value rules and allowing your original code to work.
In beta 4 I believe it was, they changed arrays to effectively always be passed by value and changed constant arrays (let) do be truly unmodifiable, which resulted in your code not working and breaking in the compile phase.
The inout keyword changes the array to be passed by reference instead of by value and changes it from being implicitly defined with let to defined with var, which means the array is now mutable, and changes to the array are seen by the caller.
Here is bubble sort implemented in swift 4.0.2
var array = [15,11,20,14,12,13,17,16,18,19]
var sortedArray = Array(array)
var sortedAboveIndex = array.count
for i in 0 ..< sortedAboveIndex-1 {
for j in 0 ..< sortedAboveIndex-i-1 {
if (sortedArray[j] > sortedArray[j+1]) {
sortedArray.swapAt(j, j+1)
}
}
}
print(sortedArray)
if any queries on above code please comment below
The function always runs O(n^2) time even if the array is sorted. It can be optimized by stopping the algorithm if inner loop didn’t cause any swap.
func main() {
var array: [Int] = [1, 3, 15, 6, 8, 12, 10, 33, 2, 88]
var swapped = false
for i in 0..<array.count {
for j in 0..<array.count - i - 1 {
if array[j] > array[j + 1] {
// let temp = array[j]
// array[j] = array[j+1]
// array[j+1] = temp
array.swapAt(j, j + 1)
swapped = true
}
}
if swapped == false {
break
}
}
print(array)
}
Swift 5: Generic bubble sort method,
func bubbleSort<T: Comparable>(with array: inout [T]) -> [T] {
for i in 1..<array.count {
for j in 0..<array.count-i where array[j] > array[j+1] {
array.swapAt(j, j+1)
}
}
return array
}
Input:-
var intArray = [8, 3, 5, 10, 4, -1, 17, 3, 18, 10]
var floatArray = [12.231, 12.23, 14.5, 3.4, 67.899, 0.0, -1.234]
var doubleArray = [123.43555, 123.1223332, -121.2212, 23.343434, 1.232434]
var stringArray = ["Ratheesh", "Srini", "Thangu", "Muthu", "Gopi"]
print(bubbleSort(with: &intArray))
print(bubbleSort(with: &floatArray))
print(bubbleSort(with: &doubleArray))
print(bubbleSort(with: &stringArray))
Output:-
[-1, 3, 3, 4, 5, 8, 10, 10, 17, 18]
[-1.234, 0.0, 3.4, 12.23, 12.231, 14.5, 67.899]
[-121.2212, 1.232434, 23.343434, 123.1223332, 123.43555]
["Gopi", "Muthu", "Ratheesh", "Srini", "Thangu"]
100% working tested code
func bubbleSort(arrValue:[Int])->[Int]{
var arr = arrValue
for i in 0..<arr.count-1{
for j in 0..<arr.count-i-1{
if arr[j] > arr[j+1]{
arr.swapAt(j, j+1)
}
}
}
print(arr)
return arr
}
Here is a way to sort in place anything Comparable.
extension Array where Element: Comparable {
mutating func bubble(by areInIncrreasingOrder: (Element, Element) -> Bool) {
for i in (0 ..< count) {
for j in (0 ..< count - i - 1) where !areInIncrreasingOrder(self[j], self[j + 1]) {
swapAt(j, j + 1)
}
}
}
}
Quick check:
var arr = (0...8).map{ _ in Int.random(in: 0...100)}
arr
arr.bubble(by: <)
arr.sorted(by: <)