Hi I have the following
class MyClass {
var myString: String?
}
var myClassList = [String: MyClass]()
I would like to sort this array alphabetically by the myString variable in Swift 3 any pointers?
As mentioned above, you have a dictionary, not tuples.
However, Dictionaries do indeed have a sorted(by:) method that you can use to sort an array of Key/Value pair tuples. Here's an example:
var m: [String: Int] = ["a": 1]
let n = m.sorted(by: { (first: (key: String, value: Int), second: (key: String, value: Int)) -> Bool in
return first.value > second.value
})
That's expanded to show the full signature of the closure, however easily shorthanded to:
let n = m.sorted(by: {
return $0.value > $1.value
})
Additionally, you can also perform other enumerations over Dictionaries
m.forEach { (element: (key: String, value: Int)) in
print($0.value)
}
All of this is due to the Collection and sequence protocol hierarchies in Swift, they're some pretty nice abstractions.
Cool problem! Though i'd like to point out first that [String: MyClass] is a Dictionary and not at Tupule.
Swift does, however, support Tupules. The syntax for your tupule would look like so:
var tupule: (String, MyClass) = (foo, bar)
You would then need to make an Array of them:
var tupules:[(String, MyClass)] = [(foo, bar), (up, dog)]
Then you could sort that array:
tupules.sort({ $0[1].myString > $1[1].myString })
though you should probably define a more robust sort mechanism.
These are the contents of the sort closure:
$0 is the one of the objects for which needs to be compared, $1 is the other.
$0[1] and $1[1] accesses the objects' 1 index, in this case, as defined in your tupule, it is your custom object MyClass
Hope this helps.
Swift version 5.2.4
let arr = [(0, 5), (1, 2), (2, 4), (3, 1), (4, 3)] // -> [(3, 1), (1, 2), (4, 3), (2, 4), (0, 5)]
let sorted = arr.sorted{ $0.1 < $1.1 }
Related
Given I've got an array in Swift such as [1,2,3,4], a method pairs() will transform it in to the array of tuples: [(1,2), (2,3), (3,4)].
Here are some more examples of how pairs() should behave:
pairs([]) should return [] as it has no pairs.
pairs([1]) should also return [], as it has no pairs.
pairs([1,2]) should be [(1,2)]. It has just one pair.
I can write code to do this for Array, but I'd like to have pairs() available as an extension on Sequence, so that it returns a Sequence of the pairs. This would make it useable on any sequence, and compatible with methods such as map, reduce, filter, etc.
How do I go about creating a Sequence like this? And how do I write the method to transform any Sequence in this way so that it can be used as flexibly as possible?
We can use zip() and dropFirst() if we define an extension
on the Collection type:
extension Collection {
func pairs() -> AnySequence<(Element, Element)> {
return AnySequence(zip(self, self.dropFirst()))
}
}
Example:
let array = [1, 2, 3, 4]
for p in array.pairs() {
print(p)
}
Output:
(1, 2)
(2, 3)
(3, 4)
More examples:
print(Array("abc".pairs()))
// [("a", "b"), ("b", "c")]
print([1, 2, 3, 4, 5].pairs().map(+))
// [3, 5, 7, 9]
print([3, 1, 4, 1, 5, 9, 2].pairs().filter(<))
// [(1, 4), (1, 5), (5, 9)]
(Unlike I wrote in the first version of this answer ...) this
approach is not safe when applied to a Sequence, because it is
not guaranteed that a sequence can be traversed multiple times
non-destructively.
Here is a direct implementation with a custom iterator type
which works on sequences as well:
struct PairSequence<S: Sequence>: IteratorProtocol, Sequence {
var it: S.Iterator
var last: S.Element?
init(seq: S) {
it = seq.makeIterator()
last = it.next()
}
mutating func next() -> (S.Element, S.Element)? {
guard let a = last, let b = it.next() else { return nil }
last = b
return (a, b)
}
}
extension Sequence {
func pairs() -> PairSequence<Self> {
return PairSequence(seq: self)
}
}
Example:
print(Array([1, 2, 3, 4].pairs().pairs()))
// [((1, 2), (2, 3)), ((2, 3), (3, 4))]
I have two Arrays of Key/Value Pairs Array[(String, Int)] that I want to join, but only return the minimum value when there's a match on the key.
val a = Array(("personA", 1), ("personB", 4), ("personC", 5))
val b = Array(("personC", 4), ("personA", 2))
Goal: c = Array((personA, 1), (personC, 4))
val c = a.join(b).collect()
results in: c = Array((personA, (1, 2)), (personC, (5, 4)))
I've tried to achieve this using the join method but am having difficulties reducing the values after they have been joined into a single array: Array[(String, (Int, Int))].
Try this:
val a = Array(("personA", 1), ("personB", 4), ("personC", 5))
val b = Array(("personC", 4), ("personA", 2))
val bMap = b.toMap
val cMap = a.toMap.filterKeys(bMap.contains).map {
case(k, v) => k -> Math.min(v, bMap(k))
}
val c = cMap.toArray
The toMap method converts the Array[(String, Int)] into a Map[String, Int]; filterKeys is then used to retain only the keys (strings) in a.toMap that are also in b.toMap. The map operation then chooses the minimum value of the two available values for each key, and creates a new map associating each key with that minimum value. Finally, we convert the resulting map back to an Array[(String, Int)] using toArray.
UPDATED
BTW: I'm not sure where you get the Array.join method from: Array doesn't have such a method, so a.join(b) doesn't work for me. However, I suspect that a and b might be Apache Spark PairRDD collections (or something similar). If that's the case, then you can join a and b, then map the values to the minimum of each pair (a reduce operation is not what you want) as follows:
a.join(b).mapValues(v => Math.min(v._1, v._2)).collect
collect converts the result into an Array[(String, Int)] as you require.
I have an array of tuples where the tuple contains some optional values:
let arrayOfTuples: [(Int, String?, String?)] = ...
How can I best remove from the array those tuples where the second element of the tuple is nil (no matter if the 3rd element is nil)?
When I use flatMap like
let flatTuplesArray: [(Int, String, String)] = arrayOfTuples.flatMap({ ($0, $1, $2) }) then a tuple does not appear in the resulting flatTuplesArray if the second or third element of the tuple is nil.
I want to apply flatMap only on the first two elements of the tuple ($0 and $1) but the result array should still have tuples with three elements (and contain "" for $2 nil values).
You can use Optional.map on the second tuple element to either unwrap
it or have it removed (by the outer flatMap), and the nil-coalescing ?? on the third tuple element
to replace nil by an empty string:
let arrayOfTuples: [(Int, String?, String?)] = [(1, "a", "b"), (2, nil, "c"), (3, "d", nil)]
let flatTuplesArray = arrayOfTuples.flatMap {
t in t.1.map { (t.0, $0, t.2 ?? "") }
}
print(flatTuplesArray)
// [(1, "a", "b"), (3, "d", "")]
If t.1 is nil then t.1.map {...} evaluates to nil and is
ignored by flatMap. Otherwise t.1.map {...} evaluates to the
value of the closure, with $0 being the unwrapped second
tuple element.
Probably, filter can help you:
let arrayOfTuples: [(Int, String?, String?)] = [(1, nil, nil), (2, "", nil)]
let result = arrayOfTuples.filter({ $0.1 != nil })
print(result) // [(2, Optional(""), nil)]
I am trying to make an array of arrays where each nested array has a string and an integer.
I have seen you can use structs but all I want to do is make them a constant, and I want to know if there is a way to do it without having to type loads of extra stuff
let items: [[String, Int]] = [["A", 1], ["B", 2], ["C", 3]]
I think what you want is an array of tuples, not an array of arrays. That implementation would look like this:
let items: [(String, Int)] = [("A", 1), ("B", 2), ("C", 3)]
You could access these properties like this:
let itemOneString = items[0].0 // "A"
let itemOneInt = items[0].1 // 1
It will work for you:
let items: [[(String, Int)]] = [[("A", 1)], [("B", 2)], [("C", 3)]]
Array is collection of similar data types. It can not contain heterogeneous types data.
But if you still want to do it. There are other workarounds like create array of dictionary like this.
let items: [[String: Any]] = [["String" : "A", "Int" : 1], ["String" : "B", "Int" : 2]]
or create an array of Tuples.
let items: [(String, Int)] = [("A", 1), ("B", 2), ("C", 3)]
You can add any number of items in Tuple or Dictionary.
I am looking for a way to see if a value (stored in a dictionary) is in an array. The array looks like this: var array = Array<Dictionary<String, Int>>()
I looked around here, on stackoverflow, and found this: How to check if an element is in an array. Only problem is I can't seem to use the contains method by writing arrray.contains.... What am I doing wrong?
You can use contains within contains to check if any of the dictionaries in an array contains the value you are looking for.
For example, to search array a for the value 1:
let a: [[String: Int]] = [["a": 1, "b": 2], ["c": 3], ["d": 4]]
Swift 1.2:
if contains(a, {contains($0.values, 1)}) {
println("it is in there")
}
Swift 2.0:
/* Thanks to #Qbyte for providing this solution */
if a.contains({ $0.values.contains(1) }) {
print("it is in there")
}
This works because each member of array a gets evaluated with the closure {contains($0.values), 1} to see if it is true. The closure takes the dictionary it is passed, gets the array of values from it and then uses contains to see if the value is in there.
You can use this extension:
extension Array {
func contains<T where T : Equatable>(obj: T) -> Bool {
return self.filter({$0 as? T == obj}).count > 0
}
}
Which you can test like:
var array1 = Array<Dictionary<String, Int>>()
array1 = [["zero": 0],["one": 1], ["two": 2]]
array1.contains(["zero": 0]) //true
array1.contains(["five": 5]) //false