Take an array and add a value to each item? - swift

Not sure if I worded that right, anyway I have an array with integers.
I need to add/multiply/divide/subtract a value from every item in the array.
So like this:
start with
var listOfInts = [1, 2, 3, 4, 5, 6]
and add 3 to every item, resulting in
listOfInts = [4,5,6,8,9]
How would I go about doing this?
Any help would be greatly appreciated, this has been frustrating since I normally can figure out these things by myself but I'm relatively new to Swift.

Map to new array:
var newListOfInts = listOfInts.map({ $0 + 3 })
Mutate same array: listOfInts = listOfInts.map({ $0 + 3 })

If you want to mutate your array instead of creating a new one (like map does), just use a for loop to walk through and change the value at each index:
var listOfInts = [1, 2, 3, 4, 5, 6]
for i in 0 ..< listOfInts.count {
listOfInts[i] += 3
}
print(listOfInts) // prints "[4, 5, 6, 7, 8, 9]"
This can be written as a one-liner like this:
(0 ..< listOfInts.count).forEach { listOfInts[$0] += 3 }
If you need to do something more with the value, you can use enumerate() to access a series of (index, value) tuples:
// Example: Replace each element with 60/value
listOfInts.enumerate().forEach { (i, v) in listOfInts[i] = 60 / v }
// This is the equivalent using a for loop
for (i, v) in listOfInts.enumerate() {
listOfInts[i] = 60 / v
}

Related

Using Swift Get array of non repeating numbers from array of numbers

Example.
let numArray = [1,2,3,3,4,5,5]
From above array create array of non- repeating number using swift. But I don't want to use Set.
Expected output is [1,2,4]
You may try the following:
let numArray = [1, 2, 3, 3, 4, 5, 5]
// Group by value
let grouped = Dictionary(grouping: numArray, by: { $0 })
// Filter by its count, convert back to Array and sort
let unique = Array(grouped.filter { $1.count == 1 }.map(\.key)).sorted()
print(unique) // [1, 2, 4]
Here is an alternative way without using higher order functions:
let numArray = [1, 2, 3, 3, 4, 5, 5]
// Group by value
let grouped = Dictionary(grouping: numArray, by: { $0 })
var uniqueArray = [Int]()
for (key, value) in grouped {
if value.count == 1 {
uniqueArray.append(key)
}
}
print(uniqueArray.sorted()) // [1, 2, 4]

Map and split values in array

How I can map a array and, in same closure, split the values in two variables?
This code work, but, I want use only one closure, not three.
let array = [1, 2, 3, 4]
let a = array.map { v -> (Int, Int) in
(v * 2, v * 10)
}
let x = a.map { $0.0 }
let y = a.map { $0.1 }
Here's a possibly less readable, but arguably more functional-style solution (immutable arrays, no for-each loop, pure function that only acts on its inputs and doesn't create side effects outside the closure):
let array = [1, 2, 3, 4]
let (x, y) = array.reduce(([Int](), [Int]())){ (result, int) in (result.0 + [int*2], result.1 + [int*10]) }
print(x) // [2, 4, 6, 8]
print(y) // [10, 20, 30, 40]
It also meets your requirement of using just one closure
Try this:
let array = [1, 2, 3, 4]
var x = [Int]()
var y = [Int]()
array.forEach() {
x.append($0 * 2)
y.append($0 * 10)
}
print(x[0]) // 2
print(y[0]) // 10
...
You can use tuple assignment to achieve this:
let array = [1, 2, 3, 4]
let (x, y) = (array.map{$0 * 2}, array.map{$0 * 10})
print(x, y)

Remove multiple indices from array

I have an array and I want to remove a bunch of indices
var arr = [0,1,2,3,4,5,6]
var rmIndices = [1,4,5]
What is the best way to remove indices 1,4,5 from arr?
Note that PermutationGenerator is going away in Swift 3 and also doesn't keep the ordering the same, though perhaps it did at one time. Using the accepted answer results in [2, 6, 0, 3] which may be unexpected. A couple of alternative approaches that give the expected result of [0, 2, 3, 6] are:
let flatArr = arr.enumerate().flatMap { rmIndices.contains($0.0) ? nil : $0.1 }
or
let filterArr = arr.enumerate().filter({ !rmIndices.contains($0.0) }).map { $0.1 }
Rather than a list of indices to remove, it may be easier to have a list of indices to keep, which you can do using the Set type:
let rmIndices = [1,4,5]
let keepIndices = Set(arr.indices).subtract([1,4,5])
Then you can use PermutationGenerator to create a fresh array of just those indices:
arr = Array(PermutationGenerator(elements: arr, indices: keepIndices))
rmIndices.sort({ $1 < $0 })
for index in rmIndices
{
arr.removeAtIndex(index)
}
Note that I've sorted the indices in descending order. This is because everytime you remove an element E, the indices of the elements beyond E reduce by one.
For Swift 3
var arr = [0,1,2,3,4,5,6]
let rmIndices = [1,4,5]
arr = arr.filter{ !rmIndices.contains($0) }
print(arr)
if you want to produce output very fastly then you can use
var arr = [0,1,2,3,4,5,6]
let rmIndices = [1,4,5]
arr = Array(Set(arr).subtracting(rmIndices))
print(array)
But it will change order of your array
Remove elements using indexes array:
Array of Strings and indexes
let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
let indexAnimals = [0, 3, 4]
let arrayRemainingAnimals = animals
.enumerated()
.filter { !indexAnimals.contains($0.offset) }
.map { $0.element }
print(arrayRemainingAnimals)
//result - ["dogs", "chimps", "cow"]
Array of Integers and indexes
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let indexesToRemove = [3, 5, 8, 12]
numbers = numbers
.enumerated()
.filter { !indexesToRemove.contains($0.offset) }
.map { $0.element }
print(numbers)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Remove elements using element value of another array
Arrays of integers
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Arrays of strings
let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
let arrayRemoveLetters = ["a", "e", "g", "h"]
let arrayRemainingLetters = arrayLetters.filter {
!arrayRemoveLetters.contains($0)
}
print(arrayRemainingLetters)
//result - ["b", "c", "d", "f", "i"]
In Swift 4:
let newArr = arr.enumerated().compactMap {
rmIndices.contains($0.0) ? nil : $0.1
}
enumerated() generates (index, value) pairs
compactMap concatenates non-nil values
In the closure, $0.0 is the index (first element of enumerated pair) as $0.1$ is the value
compactMap gathers values whose indices are not found in rmIndices
The problem with flatmap is that it gives incorrect results if your array contains optionals.
The following is much faster than the functional style solutions provided and works with optionals. You just have to make sure rmIndices is sorted and unique. It's also fairly language agnostic.
var numRemoved: Int = 0
for index in rmIndices {
let indexToRemove = index - numRemoved
arr.remove(at: indexToRemove)
numRemoved += 1
}
If you need to make sure rmIndices is sorted and unique:
rmIndices = Set(rmIndices).sorted()
Using XCTest to remove 500 elements (including the operation to ensure uniqueness and sorted):
0.006 sec
vs.
arr.enumerated().filter({ !rmIndices.contains($0.0) }).map { $0.1 }:
0.206 sec
I use this as an extension on Array
extension Array {
mutating func remove(at indices: [Int]) {
let rmIndices = Set(indices).sorted()
var numRemoved: Int = 0
for index in rmIndices {
let indexToRemove = index - numRemoved
self.remove(at: indexToRemove)
numRemoved += 1
}
}
}
Using lodash https://lodash.com/
var arr = [0,1,2,3,4,5,6]
var rmIndices = [1,4,5]
_.pullAt(arr, rmIndices);

Multidimensional arrays in Swift - Style

There are several idioms for declaring multidimensional arrays in Swift. Consider the following:
var ia1 = Array<Array<Int>>()
var ia2: Int[][] = []
typealias IntArray = Array<Int>
var ia3 = IntArray[]()
var ia4 = Int[][]()
ia1 += [[1, 2, 3], [2, 3, 4]]
ia2 += [[1, 2, 3], [2, 3, 4]]
ia3 += [[1, 2, 3], [2, 3, 4]]
ia4 += [[1, 2, 3], [2, 3, 4]]
let test = (ia1 == ia2) // true
let test2 = (ia3 == ia4) //true
// etc...
Is there actually any difference between the declarations that may bite the developer? And if not, is there any good reason to use one other over the others?
T[] is just syntactic sugar for Array<T> — there's no difference in implementation. Which style you prefer is a question of opinion.
Note that depending on what you're trying to model, multidimensional arrays might not be what you're looking for. It might make more sense to use a single array internally, and expose a multidimensional subscript to users of your data structure:
class GameBoard {
let width = 10
let height = 10
let board: [Int]
init() {
board = [Int](count: width * height, repeatedValue: 0)
}
subscript(i: Int, j: Int) -> Int {
return board[i + j * width]
}
}
let b = GameBoard()
b[0,0]
b[4,1]

Shuffling part of an ArrayBuffer in-place

I need to shuffle part of an ArrayBuffer, preferably in-place so no copies are required. For example, if an ArrayBuffer has 10 elements, and I want to shuffle elements 3-7:
// Unshuffled ArrayBuffer of ints numbered 0-9
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
// Region I want to shuffle is between the pipe symbols (3-7)
0, 1, 2 | 3, 4, 5, 6, 7 | 8, 9
// Example of how it might look after shuffling
0, 1, 2 | 6, 3, 5, 7, 4 | 8, 9
// Leaving us with a partially shuffled ArrayBuffer
0, 1, 2, 6, 3, 5, 7, 4, 8, 9
I've written something like shown below, but it requires copies and iterating over loops a couple of times. It seems like there should be a more efficient way of doing this.
def shufflePart(startIndex: Int, endIndex: Int) {
val part: ArrayBuffer[Int] = ArrayBuffer[Int]()
for (i <- startIndex to endIndex ) {
part += this.children(i)
}
// Shuffle the part of the array we copied
val shuffled = this.random.shuffle(part)
var count: Int = 0
// Overwrite the part of the array we chose with the shuffled version of it
for (i <- startIndex to endIndex ) {
this.children(i) = shuffled(count)
count += 1
}
}
I could find nothing about partially shuffling an ArrayBuffer with Google. I assume I will have to write my own method, but in doing so I would like to prevent copies.
If you can use a subtype of ArrayBuffer you can access the underlying array directly, since ResizableArray has a protected member array:
import java.util.Collections
import java.util.Arrays
import collection.mutable.ArrayBuffer
val xs = new ArrayBuffer[Int]() {
def shuffle(a: Int, b: Int) {
Collections.shuffle(Arrays.asList(array: _*).subList(a, b))
}
}
xs ++= (0 to 9) // xs = ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
xs.shuffle(3, 8) // xs = ArrayBuffer(0, 1, 2, 4, 6, 5, 7, 3, 8, 9)
Notes:
The upper bound for java.util.List#subList is exclusive
It's reasonably efficient because Arrays#asList doesn't create a new set of elements: it's backed by the array itself (hence no add or remove methods)
If using for real, you probably want to add bounds-checks on a and b
I'm not entirely sure why it must be in place - you might want to think that over. But, assuming it's the right thing to do, this could do it:
import scala.collection.mutable.ArrayBuffer
implicit def array2Shufflable[T](a: ArrayBuffer[T]) = new {
def shufflePart(start: Int, end: Int) = {
val seq = (start.max(0) until end.min(a.size - 1)).toSeq
seq.zip(scala.util.Random.shuffle(seq)) foreach { t =>
val x = a(t._1)
a.update(t._1, a(t._2))
a(t._2) = x
}
a
}
}
You can use it like:
val a = ArrayBuffer(1,2,3,4,5,6,7,8,9)
println(a)
println(a.shufflePart(2, 7))
edit: If you're willing to pay the extra cost of an intermediate sequence, this is more reasonable, algorithmically speaking:
def shufflePart(start: Int, end: Int) = {
val seq = (start.max(0) until end.min(a.size - 1)).toSeq
seq.zip(scala.util.Random.shuffle(seq) map { i =>
a(i)
}) foreach { t =>
a.update(t._1, t._2)
}
a
}
}