How to sum all elements in a tuple - swift

In Swift, i.e. a tuple let tp = (2,5,8).
What's the simplest and smartest way to sum it up, other than traditionaly as below?
let sum = tp.0 + tp.1 + tp.2

Your approach is the most straightforward. An alternative is harder to read, but it works, too:
let s = Mirror(reflecting: x).children.map {$1 as! Int}.reduce(0,+)
Mirror(reflecting: x).children obtains a sequence of name-value pairs representing the original tuple. Each element of the sequence is a (String,Any) tuple. map {$1 as! Int} converts this sequence to a sequence of Ints representing tuple element values; reduce(0,+) produces the sum of these values.
You can combine map and reduce in a single expression for something even less readable:
let s = Mirror(reflecting: x).children.reduce(0,{$0.1.value as! Int + $0.0})
Note: It goes without saying that this crashes at runtime for tuples containing values of type other than Int.

Related

Finding the average of option values containg object in a list

I'm new to Scala and I have been struggling with Option and Lists. I have the following object:
object Person {
case class Person(fName: String,
lName: String,
jeans: Option[Jeans],
jacket: Option[Jacket],
location: List[Locations],
age: Int)
case class Jeans(brand: String, price: Int, color: String)
...
}
And I'm trying to write the function that takes as input list of type person and return the average price of their jeans:
def avgPriceJeans(input: List[Person]): Int
When you have a list of values and want to reduce all of them to a single value, applying some kind of operation. You need a fold, the most common one would be a foldLeft.
As you can see in the scaladoc. This method receives an initial value and a combination function.
It should be obvious that the initial value should be a zero. And that the combination function should take the current accumulate and add to it the price of the current jeans.
Nevertheless, now we have another problem, the jeans may or may not exists, thus we use option. In this case we need a way to say if they exists give me their price, if not give a default value (which in this case makes sense to be another zero).
And that is precisely what Option.fold give us.
Thus we end with something like:
val sum = input.foldLeft(0) {
(acc, person) =>
acc + person.jeans.fold(ifEmpty = 0)(_.price)
}
Now that you need the average, you only need to divide that sum with the count.
However, we can do the count in the same foldLeft, just to avoid an extra iteration.
(I changed the return type, as well as the price property, to Double to ensure accurate results).
def avgPriceJeans(input: List[Person]): Double = {
val (sum, count) = input.foldLeft((0.0d, 0)) {
case ((accSum, accCount), person) =>
(
accSum + person.jeans.fold(ifEmpty = 0.0d)(_.price),
accCount + 1
)
}
sum / count
}
As #SethTissue points out, this is relatively straightforward:
val prices = persons.flatMap(_.jeans.map(_.price))
prices.sum.toDouble / prices.length
The first line needs some unpicking:
Taking this from the inside out, the expression jeans.map(_.price) takes the value of jeans, which is Option[Jeans], and extracts the price field to give Option[Int]. The flatMap call is equivalent to map followed by flatten. The map call applies this inner expression to the jeans field of each element of persons. This turns the List[Person] into a List[Option[Int]]. The flatten call extracts all the Int values from Some[Int] and discards all the None values. This gives List[Int] with one element for each Person that had a non-empty jeans field.
The second line simply sums the values in the List, converts it to Double and then divides by the length of the list. Adding error checking is left as an exercise!
One approach consist in calculate the value of the jeans price for each element of the list.
After that you can sum all the values (with sum method) and divide by the list size.
I managed the case when jeans is None with 0 as price value (so I consider it for the sum).
Here the code:
def avgPriceJeans(input: List[Person]): Int =
input.map(_.jeans.map(_.price).getOrElse(0)).sum / input.size

Determining type of map output

I am trying to determine what the type of .map's output is here:
func position(rows: Int, cols: Int) -> [Position] {
return (0 ..< rows)
.map {
zip(
[Int](repeating: $0, count: cols) ,
0 ..< cols
)
}
}
I know that zip returns a Zip2Sequence instance, which in this case is tuple pairs of (integer array, countable integer range).
I get that map alters elements in a sequence, but I thought it took multiple arguments like val in val * 2 and here zip is the only argument... so is it just adding the output of zip to an array?
The result of the map is of type Array<Zip2Sequence<Array<Int>, CountableRange<Int>>> which is essentially [[(Int, Int)]].
I found this by assigning the result of the map to let result and printing print(type(of: result)).
map transforms your original sequence (0 ..< rows) into an array that will have rows items. zip will be called with each element of (0 ..< rows) in turn which is represented by $0.
It will be more useful if you wrap the zip call with Array() to turn the zip sequence into an actual array that you can examine easily:
Example:
let rows = 2
let cols = 3
let result = (0 ..< rows)
.map { val in
Array(zip(
[Int](repeating: val, count: cols) ,
0 ..< cols
))
}
print(result)
// [[(0, 0), (0, 1), (0, 2)], [(1, 0), (1, 1), (1, 2)]]
The type of (0 ..< rows) is CountableRange<Int>:
1> (0 ..< 10)
$R0: (CountableRange<Int>) = {
lowerBound = 0
upperBound = 10
}
CountableRange conforms to Sequence, so it has a map method. This map method takes one argument, a closure.
A closure is a function. In general, a function has zero or more arguments and a one return value. For CountableRange<Int>.map, the closure is required to take one argument of type Int and can return any type.
There are several ways to write closures in Swift. The shortest way, which your example uses, is to write a single expression inside { ... }. Here's what The Swift Programming Language (Swift 4) says:
Implicit Returns from Single-Expression Closures
Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration[…]
Furthermore, if the closure takes arguments, the closure can refer to them using shorthand names ($0, $1, etc.) instead of giving them explicit names (e.g. val in ...). From the book again:
Shorthand Argument Names
Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.
If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body[…]
Looking at the map method call, we can see that its closure contains a single expression (a call to zip) with implicit return, and it uses $0 to refer to its single argument.
The zip function takes two arguments, each of which must be a Sequence, and the zip function returns a Zip2Sequence. In your example, the first argument to zip is [Int](repeating: $0, count: cols), which has type [Int] (or Array<Int>). The second argument to zip is 0 ..< cols, which is another CountableRange<Int>. So the type returned by this call to zip is Zip2Sequence<[Int], CountableRange<Int>>, which is a somewhat inscrutable type that generates tuples (Int, Int).
The type returned by map is an Array containing the values returned by its closure argument. Thus the type returned by map in this case is [Zip2Sequence<[Int], CountableRange<Int>>].
If you want something more scrutable, you can wrap the call to zip in the Array constructor:
func position(rows: Int, cols: Int) -> [[(Int, Int)]] {
return (0 ..< rows)
.map {
Array(zip(
[Int](repeating: $0, count: cols) ,
0 ..< cols
))
}
}
The Array constructor takes any Sequence and turns it into an Array. So the Zip2Sequence<[Int], CountableRange<Int>> is turned into [(Int, Int)], and map produces an Array whose elements are that type, thus producing an array of arrays of pairs of Int, or [[(Int, Int)]].

Swift: how to count the number of elements in Tuple

I was wondering if there is a method or function in Swift which can count the number of elements in the tuple.
Reason of question:
I have a tuple called "tople"
What I want to do is to load the elements into variables (by using for loop, where you actually need the number of elements)
And then use this in a function.
Additional questions, can you use tuples to load variables into the function and/or to return them from a function?
var tople = (1,2,3)
func funkce (a:Int, b:Int, c: Int){
println(a)
println(b)
println(c)
}
funkce(a,b,c)
Thanks and I do appreciate any helpful comment.
In Swift 3 you count the number of elements in a tuple like this:
let myTuple = (1,2,3,4)
let size = Mirror(reflecting: myTuple).children.count
Yes, you can load tuples into variables.
let (a, b, c) = (1, 2, 3)
To extract values from a tuple, you can use MirrorType. You can find more here.
let tuple = (1, 2, 3)
let count = Mirror(reflecting: tuple).children.count // 3

Swift enumerate functions. How does it work behind?

The enumerate function returns a tuple for each item in the array composed of the index and the value for that item.
The map function returns an array of elements built from the results of applying a provided transforming closure for each element in the array.
Declaration:
func map<U>(transform: (T) -> U) -> [U]
var numbers = [1, 2, 3]
numbers = map(numbers) { (index, element) in
index + element
} //[1, 3, 5]
That is good. Works.
var numbers = [1, 2, 3]
var result = map(enumerate(numbers)) { (index, element) in
index + element
} //[1, 3, 5]
map expects an array as a first parameter, but I put there the tuple as a result of enumerate fnction.
The question is: WHY IT WORKS?
It works because in addition to array having a map method, there is a map function that takes any kind of SequenceType:
func map<S : SequenceType, T>(source: S, transform: (S.Generator.Element) -> T) -> [T]
This works not just with arrays, but any kind of sequence – strings, ranges, zipped pairs of sequences, and the result of enumerate, which is also a sequence:
// enumerate is a function that takes any kind of sequence, and returns
// an EnumerateSequence object
func enumerate<Seq : SequenceType>(base: Seq) -> EnumerateSequence<Seq>
EnumerateSequence is a type that holds on to another sequence (in your case, the array [1,2,3]) and then when asked to generate an element, generates the next element from it’s contained sequence along with an incrementing number.
You want to look at the following answer: What's the cleanest way of applying map() to a dictionary in Swift?
The map function works on the tuple because it is using the map function from the swift standard library that works on any SequenceType. So it is actually using the index and value of the enumeration, which are the same as the index and element that the map function would use when looking at an array input.

How to sort an ArrayBuffer[Double] and save indices

Given an ArrayBuffer[Double], how can sort its elements with maintaining also their indices, e.g.
val arr ArrayBuffer[Double] = ArrayBuffer(4,5.3,5,3,8,9)
the result has to be:
arrSorted = ArrayBuffer(3,4,5,5.3,8,9)
indices = Arraybuffer(3,0,2,1,4,5) //here the data structure doesn't matter, it can be Array, List, Vector, etc.
Thanks
This is a one-liner:
val (addSorted, indices) = arr.zipWithIndex.sorted.unzip
Going step by step, zipWithIndex creates a collection of tuples with the index as the second value in each tuple:
scala> println(arr.zipWithIndex)
ArrayBuffer((4.0,0), (5.3,1), (5.0,2), (3.0,3), (8.0,4), (9.0,5))
sorted sorts these tuples lexicographically (which is almost certainly what you want, but you could also use sortBy(_._1) to be explicit about the fact that you want to sort by the values):
scala> println(arr.zipWithIndex.sorted)
ArrayBuffer((3.0,3), (4.0,0), (5.0,2), (5.3,1), (8.0,4), (9.0,5))
unzip then turns this collection of tuples into a tuple of collections, which you can deconstruct with val (addSorted, indices) = ....