Can someone please explain what the major differences there are between Tuples and Dictionaries are and when to use which in Swift?
Major difference:
If you need to return multiple values from a method you can use tuple.
Tuple won't need any key value pairs like Dictionary.
A tuple can contain only the predefined number of values, in dictionary there is no such limitation.
A tuple can contain different values with different datatype while a dictionary can contain only one datatype value at a time
Tuples are particularly useful for returning multiple values from a function. A dictionary can be used as a model object.
There are two types of Tuple:
1 Named Tuple
In Named tuple we assign individual names to each elements.
Define it like:
let nameAndAge = (name:"Midhun", age:7)
Access the values like:
nameAndAge.name
nameAndAge.age
2 Unnamed Tuple
In unnamed tuple we don't specify the name for it's elements.
Define it like:
let nameAndAge = ("Midhun", 7)
Access the values like:
nameAndAge.0
nameAndAge.1
or
let (theName, thAge) = nameAndAge
theName
thAge
Reference:
Tuple
Tuples enable you to create and pass around groupings of values. You
can use a tuple to return multiple values from a function as a single
compound value.
You can check more about Tuple in Swift Programming Language
Dictionary
A dictionary is a container that stores multiple values of the same
type. Each value is associated with a unique key, which acts as an
identifier for that value within the dictionary
You can check more about Dictionary in Swift CollectionTypes
A tuple is completely predefined: it can only have the names and number of values you've predefined for it, though they can be different value types, and they don't have to have names. And the names are literals.
A dictionary can have any number of key-value pairs, of one value type. And the keys can be referred to through variables.
Here's a tuple (with names):
typealias MySillyTuple = (theInt:Int, theString:String)
That's it. There is one Int called theInt, one String called theString, and that is exactly what it must have, no more, no less. And the only way to access the values by name is as a literal: t.theInt. If you have a string "theInt", you can't use it to access t.theInt.
Here's a Dictionary:
var d = [String:String]()
Now d can have any number of keys, and any keys, from none to a gazillion. And the keys can be specified using string variables; you don't have to know in advance what a key will be. And all the values must be strings.
So basically I would say a tuple is nothing like a dictionary. A dictionary is a complex beast for look up by dynamic keys. A tuple is just a value that is more than one value.
Dictionary is Collection Type, Tuple is Compound type.
Dictionary is Key Value type, Tuple is Comma separated list of multiple types
Dictionary:
var dictionary = ["keyone": "value one", "keytwo": "Value Two"]
Tuple:
let someTuple: (Double, Double, String, (Int, Int)) = (3.14159, 2.71828, "Hello", (2, 3))
A dictionary is made up of key-value sets. A tuple is made for passing grouped values.
Dictionaries:
A dictionary is a container that stores multiple values of the same
type. Each value is associated with a unique key, which acts as an
identifier for that value within the dictionary.
A dictionary should be used for creating lists of associated objects. An example use would be a dictionary of players and their scores:
var scoreDictionary = ["Alice" : 100, "Bob" : 700]
Tuples:
Tuples group multiple values into a single compound value.
A tuple should be used for passing groups of values. They are similar to arrays, but are fixed-length and immutable. An example use might be a tuple representing a 3-dimensional point:
var myPoint = (10, 12, 14)
As you can see there are many cases in which you would use a dictionary and many cases in which you would use a tuple. Each has its own specific purpose.
Tuples are compound values, and can be useful for functions returning several values from a function. e.g. (from the Apple Docs):
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
This function returns a tuple containing min, max and sum. These values can be accessed either by name or position:
let statistics = calculateStatistics([5, 3, 100, 3, 9])
var sum:Int = statistics.sum
var sum2:Int = statistics.2
Dictionaries are "lookup" data types. They return an object for a given key. For example the following code:
let font:NSFont = NSFont(name: "AppleCasual", size: 18.0)!
let textStyle = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as NSMutableParagraphStyle
textStyle.alignment = NSTextAlignment.LeftTextAlignment
let textColor:NSColor = NSColor(calibratedRed: 1.0, green: 0.0, blue: 1.0, alpha: 1.0)
let attribs = [NSFontAttributeName: font,
NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: textStyle]
let color = attribs[NSForegroundColorAttributeName]
println("color = \(color)")
Will print:
color = Optional(NSCalibratedRGBColorSpace 1 0 1 1)
Dictionaries are useful for many things and are required for some functions. For example (after the code above):
let testString:NSString = "test String"
var img:NSImage = NSImage(size: NSMakeSize(200,200))
img.lockFocus()
testString.drawAtPoint(NSMakePoint(0.0, 0.0), withAttributes: attribs)
img.unlockFocus()
In this code drawAtPoint uses the dictionary attribs to lookup the parameters it needs. The parameters don't need to be in any specific order because drawAtPoint will lookup the values it needs by using the correct key.
Dictionaries and tuples are similar, but not quite the same. In the code above the dictionary returned an Optional type:Optional(NSCalibratedRGBColorSpace 1 0 1 1)
If we use a tuple for the same purpose:
var attribTuple = (font:NSFont(name: "AppleCasual", size: 18.0), color:NSColor(calibratedRed: 1.0, green: 0.0, blue: 1.0, alpha: 1.0))
println("tupleColor = \(attribTuple.color)")
Prints:
tupleColor = NSCalibratedRGBColorSpace 1 0 1 1
Not the optional type the dictionary did.
Tuples are fixed-length things. You can’t add an extra element to a tuple or remove one. Once you create a tuple it has the same number of elements – var t = (1,2) is of type (Int,Int). It can never become (1,2,3), the most you could do is change it to, say, (7,8). This is all fixed at compile-time.
You can access the elements via their numeric positions like this
t.0 + t.1 // with (1,2), would equal 3
t.0 = 7
Arrays are variable length: you can start with an array var a = [1,2], and then add an entry via a.append(3) to make it [1,2,3]. You can tell how many items with a.count. You can access/update elements via a subscript: a[0] + a[2] // equals 4
You can name the elements in tuples:
var n = (foo: 1, bar: 2)
Then you can use those names:
n.foo + n.bar // equals 3
This doesn’t remove the ability to access them by position though:
n.0 + n.1 // equals 3
But these names, once set, are fixed at compile time just like the length:
n.blarg // will fail to compile
This is not the same as dictionaries, which (like arrays), can grow or shrink:
var d = [“foo”:1, “bar”:2]
d[“baz”] = 3;
d[“blarg”] // returns nil at runtime, there’s no such element
Related
Consider the following code:
let pair = System.Tuple.Create (10, "foo") // val pair : int * string = (10, "foo")
let tuple = System.Tuple.Create <| (10, "foo") // val tuple : System.Tuple<int * string> = ((10, "foo"))
Why doesn't the two lines yield values of the same type? Does the type of the argument (10, "foo") somehow change between the two lines?
What's the exact difference between int * string and System.Tuple<int * string>?
For 2, at least the latter has null as a value (this is how this question came up). Are there other differences?
There are two different overloads of Tuple.Create:
Tuple.Create<'T1>(item1: 'T1)
Tuple.Create<'T1, 'T2>(item1: 'T1, item2: 'T2)
In the first case you just calling a method with two arguments. So the second Tuple.Create overload is obviously picked. No surprise.
But with piping you first create a tuple instance. And then pass it to Tuple.Create method. This is what happens in the second example
let intermediate : Tuple<int, string> = (10, "foo")
let tuple = Tuple.Create(intermediate)
With a single argument the first Tuple.Create overload will be picked.
Note: star type is a way tuple type names are written in F#. So Tuple<int, string, bool> will be (int * string * bool). It's the same thing.
Your tuple is a tuple of one (1) element, namely the tuple 10,"foo". It is equivalent of
System.Tuple.Create(System.Tuple.Create(10, "foo"))
Your pair on the other hand is a tuple of the two elements 10 and "foo".
So pair has type System.Tuple<int,string> (which is the same as int * string), but tuple has type System.Tuple<System.Tuple<int,string>> (which is System.Tuple<int * string>)
Is there a way to have named key/value pairs in a Swift dictionaries? I'd rather use a name instead of an index number to refer to either the key or the value.
Unfortunately, key/value pairs by name in Dictionary in Swift only discusses referring to the keys and values in a for-loop. I'd like to give the keys and values a name when I declare them in the typealias so they can always be referred to by their names.
Please see the comment in the below code snippet to show what I mean:
typealias CalendarRules = [EKCalendar : [String]]
let calendarRules = buildCalendarRules() // builds the array.
let firstCalendarRule = calendarRules.first
print(firstCalendarRule.0) // I'd like to write: print(firstCalendarRule.cal)
print(firstCalendarRule.1) // I'd like to write: print(firstCalendarRule.theString)
This has nothing to do with dictionaries, except very indirectly; and your CalendarRules type alias is irrelevant. Your firstCalendarRule is not a dictionary; it is a tuple. You are free to name the members of a tuple:
typealias Rule = (cal:String, string:String)
let d = ["I am a calendar":"I am a string"]
let firstRule : Rule = d.first!
print(firstRule.cal) // I am a calendar
Given is a Swift Dictionary which maps an Int to a tuple. For instance:
var tuples: [Int: (Int, Int)] = [1: (1, 1), 2: (2, 2), 3: (3, 3)]
Does assigning one element of one tuple mutate internal state of the Dictionary?
tuples[1].0 = 8 // Was the dictionary itself changed now?
Further, is concurrent access on different tuples in the Dictionary thread-safe? What about concurrent access to the same tuple, but different elements of the tuple?
// Is this safe?
dispatch_async(queue1) {
tuples[1].0 = 10
}
dispatch_async(queue2) {
tuples[1].1 = 10
}
// What about this?
dispatch_async(queue1) {
tuples[1].0 = 10
}
dispatch_async(queue2) {
tuples[2].1 = 10
}
Do other Swift collections (for example Array) behave the same way? What would happen if we would use a Dictionary mapping to some object type instead of a tuple?
Yes, that does change the Dictionary. Value types that are contained in another aggregate are "part of" that aggregate, rather than a separate entity. So this applies to a tuple inside a Dictionary, an Array inside a Dictionary, etc...
Given that, no, that's not thread-safe. In practice it probably is safe as long as the Dictionary is uniquely referenced (non-uniquely referenced Dictionaries will copy their backing store when it mutates), but that's difficult-to-impossible to guarantee.
If you wrap the tuple in an object, that would be sufficient, as long as only one thread at a time acts on any given object.
Just a little example so you can see the dictionary does get changed:
var test = [1: (1, 1), 2: (2, 2), 3: (3, 3)] { didSet { print("dictionary changed") } }
test[1]?.0 = 3
// Dictionary changed
Today I was just going through some basic swift concepts and was working with some examples to understand those concepts. Right now I have completed studying tuples.
I have got one doubt i.e, what is the need of using tuples ? Ya I did some digging on this here is what I got :
We can be able to return multiple values from a function. Ok but we can also do this by returning an array.
Array ok but we can return an multiple values of different types. Ok cool but this can also be done by array of AnyObject like this :
func calculateStatistics (scores:[Int])->[AnyObject]
{
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores
{
if score > max{
max = score
}
else if score < min{
min = score
}
sum += score
}
return [min,max,"Hello"]
}
let statistics = calculateStatistics([25,39,78,66,74,80])
var min = statistics[0]
var max = statistics[1]
var msg = statistics[2] // Contains hello
We can name the objects present in the tuples. Ok but I can use a dictionary of AnyObject.
I am not saying that Why to use tuples when we have got this . But there should be something only tuple can be able to do or its easy to do it only with tuples. Moreover the people who created swift wouldn't have involved tuples in swift if there wasn't a good reason. So there should have been some good reason for them to involve it.
So guys please let me know if there's any specific cases where tuples are the best bet.
Thanks in advance.
Tuples are anonymous structs that can be used in many ways, and one of them is to make returning multiple values from a function much easier.
The advantages of using a tuple instead of an array are:
multiple types can be stored in a tuple, whereas in an array you are restricted to one type only (unless you use [AnyObject])
fixed number of values: you cannot pass less or more parameters than expected, whereas in an array you can put any number of arguments
strongly typed: if parameters of different types are passed in the wrong positions, the compiler will detect that, whereas using an array that won't happen
refactoring: if the number of parameters, or their type, change, the compiler will produce a relevant compilation error, whereas with arrays that will pass unnoticed
named: it's possible to associate a name with each parameter
assignment is easier and more flexible - for example, the return value can be assigned to a tuple:
let tuple = functionReturningTuple()
or all parameters can be automatically extracted and assigned to variables
let (param1, param2, param3) = functionReturningTuple()
and it's possible to ignore some values
let (param1, _, _) = functionReturningTuple()
similarity with function parameters: when a function is called, the parameters you pass are actually a tuple. Example:
// SWIFT 2
func doSomething(number: Int, text: String) {
println("\(number): \(text)")
}
doSomething(1, "one")
// SWIFT 3
func doSomething(number: Int, text: String) {
print("\(number): \(text)")
}
doSomething(number: 1, text: "one")
(Deprecated in Swift 2) The function can also be invoked as:
let params = (1, "one")
doSomething(params)
This list is probably not exhaustive, but I think there's enough to make you favor tuples to arrays for returning multiple values
For example, consider this simple example:
enum MyType {
case A, B, C
}
func foo() -> (MyType, Int, String) {
// ...
return (.B, 42, "bar")
}
let (type, amount, desc) = foo()
Using Array, to get the same result, you have to do this:
func foo() -> [Any] {
// ...
return [MyType.B, 42, "bar"]
}
let result = foo()
let type = result[0] as MyType, amount = result[1] as Int, desc = result[2] as String
Tuple is much simpler and safer, isn't it?
Tuple is a datastructure which is lighter weight than heterogeneous Array. Though they're very similar, in accessing the elements by index, the advantage is tuples can be constructed very easily in Swift. And the intention to introduce/interpolate this(Tuple) data structure is Multiple return types. Returning multiple data from the 'callee' with minimal effort, that's the advantage of having Tuples. Hope this helps!
A tuple is ideally used to return multiple named data from a function for temporary use. If the scope of the tuple is persistent across a program you might want to model that data structure as a class or struct.
I'm getting this error in XCode beta 3. Don't know whether this is a bug or if I'm doing something I shouldn't. Anyway, this is an example that I read on Apple's official documentation.
Here's the code:
var names = ["Mark" , "Bob" , "Tracy" , "John"]
var reversed = sort(names , { (s1: String , s2: String) -> Bool in return s1 > s2
})
It is a simple sort using a closure.
There are several problems here:
Never declare a generic without specifying its type. Don't use Array, use Array<String>. However, in this case, you don't need the : Array<String part, you don't need the typing as Array<String>. Just let the type be inferred.
let names = ["Mark", "Bob", "Tracy", "John"]
Now, this is a constant array. Array is a value type. Constant value types cannot be modified.
The sort function is trying to sort the array. It doesn't create a new array, it sorts the one you pass as a parameter. However, since it is a value type, it cannot be a constant and you have to pass it by reference:
var names = ["Mark", "Bob", "Tracy", "John"]
sort(&names, >)
If you don't want to sort the original array and you want to create a new array instead, use sorted function.
let names = ["Mark", "Bob", "Tracy", "John"]
let sortedNames = sorted(names, >)
Note this has changed substantially between Beta 2 and Beta 3.