Sorting Dictionary on two values in swift - swift

I have the following dictionary like so:
["FLBEY023": ["Position": 8, "Page": 1],
"COSMAX826": ["Position": 6, "Page": 2],
"TOVIC029": ["Position": 7, "Page": 1],
"CGLYN188": ["Position": 2, "Page": 2],
"TOORL002B": ["Position": 1, "Page": 2],
"GSTOGFU096": ["Position": 6, "Page": 1],
"COSNAI423": ["Position": 2, "Page": 1],
"COSCOL681": ["Position": 3, "Page": 2],
"TONIV170": ["Position": 4, "Page": 1],
"SUMAL086A": ["Position": 7, "Page": 2],
"PEIAM004": ["Position": 5, "Page": 1],
"FOSCI012": ["Position": 1, "Page": 1],
"FOSWI009": ["Position": 4, "Page": 2],
"GSTODOV061": ["Position": 3, "Page": 1]]
Now I'd like to sort this Dictionary for each of the product codes. But I'd like to sort it on position and page. So for example I'd like it to run position then page number for example
["FOSCI012": ["Position": 1, "Page": 1],
"COSNAI423": ["Position": 2, "Page": 1],
"GSTODOV061": ["Position": 3, "Page": 1],
....
...
...
"TOORL002B": ["Position": 1, "Page": 2],
"CGLYN188": ["Position": 2, "Page": 2],
..
How would I go about doing this using the Dictionary.sorted method. I understand how to do it to sort based on one element but not two.

Dictionaries are unordered collections and you can't sort them.
However, you can use .sorted(by:) method that returns a list of ordered tuples where each one represents a key-value entry in the dictionary:
dictionary.sorted { (lhs, rhs) -> Bool in
if (lhs.value["Page"]! == rhs.value["Page"]!) {
return lhs.value["Position"]! < rhs.value["Position"]!
} else {
return lhs.value["Page"]! < rhs.value["Page"]!
}
}
which results in sth like below:
[(key: "FOSCI012", value: ["Position": 1, "Page": 1]),
(key: "COSNAI423", value: ["Position": 2, "Page": 1]),
...
(key: "TOORL002B", value: ["Position": 1, "Page": 2]),
(key: "CGLYN188", value: ["Position": 2, "Page": 2]),
...
]
Here you can download the playground.

You can sort dictionary by key and value
extension Dictionary where Value:Comparable {
var sortedByValue:[(Key,Value)] {return Array(dict).sorted{$0.1 < $1.1}}
}
extension Dictionary where Key:Comparable {
var sortedByKey:[(Key,Value)] {return Array(dict).sorted{$0.0 < $1.0}}
}
["b":2,"a":1,"c":3].sortedByKey// output will be a:1, b:2, c:3
["b":2,"a":1,"c":3].sortedByValue//output will be a:1, b:2, c:3

Related

Using map in spark to make dictionary format

I executed the following code:
temp = rdd.map( lambda p: ( p[0], (p[1],p[2],p[3],p[4],p[5]) ) ).groupByKey().mapValues(list).collect()
print(temp)
and I could get data:
[ ("A", [("a", 1, 2, 3, 4), ("b", 2, 3, 4, 5), ("c", 4, 5, 6, 7)]) ]
I'm trying to make a dictionary with second list argument.
For example I want to reconstruct temp like this format:
("A", {"a": [1, 2, 3, 4], "b":[2, 3, 4, 5], "c":[4, 5, 6, 7]})
Is there any clear way to do this?
If I understood you correctly you need something like this:
spark = SparkSession.builder.getOrCreate()
data = [
["A", "a", 1, 2, 5, 6],
["A", "b", 3, 4, 6, 9],
["A", "c", 7, 5, 6, 0],
]
rdd = spark.sparkContext.parallelize(data)
temp = (
rdd.map(lambda x: (x[0], ({x[1]: [x[2], x[3], x[4], x[5]]})))
.groupByKey()
.mapValues(list)
.mapValues(lambda x: {k: v for y in x for k, v in y.items()})
)
print(temp.collect())
# [('A', {'a': [1, 2, 5, 6], 'b': [3, 4, 6, 9], 'c': [7, 5, 6, 0]})]
This is easily doable with a custom Python function once you obtain the temp object. You just need to use tuple, list and dict manipulation.
def my_format(l):
# get tuple inside list
tup = l[0]
# create dictionary with key equal to first value of each sub-tuple
dct = {}
for e in tup[1]:
dct2 = {e[0]: list(e[1:])}
dct.update(dct2)
# combine first element of list with dictionary
return (tup[0], dct)
my_format(temp)
# ('A', {'a': [1, 2, 3, 4], 'b': [2, 3, 4, 5], 'c': [4, 5, 6, 7]})

Use partition in Swift to move some predefined elements to the end of the Array

I would like to use the Array.partition(by:) to move some predefined elements from an array to the the end of it.
Example:
var my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let elementsToMove = [1, 3, 4, 5, 8]
// desired result: [0, 2, 6, 7, 9, ...remaining items in any order...]
Is there an elegant way to do that? Observe that elementsToMove does not follow a pattern.
partition(by:) does not preserve the order of the elements:
var my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let elementsToMove = [1, 3, 4, 5, 8]
_ = my_array.partition(by: { elementsToMove.contains($0) } )
print(my_array) // [0, 9, 2, 7, 6, 5, 4, 3, 8, 1]
A simple solution would be to filter-out and append the elements from
the second array:
let my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let elementsToMove = [1, 3, 4, 5, 8]
let newArray = my_array.filter({ !elementsToMove.contains($0) }) + elementsToMove
print(newArray) // [0, 2, 6, 7, 9, 1, 3, 4, 5, 8]
For larger arrays it can be advantageous to create a set of the
to-be-moved elements first:
let my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let elementsToMove = [1, 3, 4, 5, 8]
let setToMove = Set(elementsToMove)
let newArray = my_array.filter({ !setToMove.contains($0) }) + elementsToMove
print(newArray) // [0, 2, 6, 7, 9, 1, 3, 4, 5, 8]
If you have unique object in your my_array then you can try something like this.
var my_array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
var tempArray = my_array //Preserve original array
let elementsToMove = [1, 3, 4, 5, 8]
let p = tempArray.partition(by: elementsToMove.contains)
//Now sort first part of tempArray on basis of your my_array to get order you want
let newArray = tempArray[0..<p].sorted(by: { my_array.index(of: $0)! < my_array.index(of: $1)! }) + tempArray[p...]
print(newArray)
Output
[0, 2, 6, 7, 9, 5, 4, 3, 8, 1]

How to split `NSmutableArray` array array to chunks swift 3?

NSMutableArray *sample;
I have an NSmutableArray, and I want to split it into chunks. I have tried checking the internet didn't find the solution for it. I got the link to split integer array.
How about this which is more Swifty?
let integerArray = [1,2,3,4,5,6,7,8,9,10]
let stringArray = ["a", "b", "c", "d", "e", "f"]
let anyObjectArray: [Any] = ["a", 1, "b", 2, "c", 3]
extension Array {
func chunks(_ chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
Array(self[$0..<Swift.min($0 + chunkSize, self.count)])
}
}
}
integerArray.chunks(2) //[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
stringArray.chunks(3) //[["a", "b", "c"], ["d", "e", "f"]]
anyObjectArray.chunks(2) //[["a", 1], ["b", 2], ["c", 3]]
To Convert NSMutableArray to Swift Array:
let nsarray = NSMutableArray(array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
if let swiftArray = nsarray as NSArray as? [Int] {
swiftArray.chunks(2) //[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
}
If you wanna insist to use NSArray, then:
let nsarray = NSMutableArray(array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
extension NSArray {
func chunks(_ chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
self.subarray(with: NSRange(location: $0, length: Swift.min(chunkSize, self.count - $0)))
}
}
}
nsarray.chunks(3) //[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
You can use the subarray method.
let array = NSArray(array: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let left = array.subarray(with: NSMakeRange(0, 5))
let right = array.subarray(with: NSMakeRange(5, 5))

One trendline for multiple series

Hello I have this simple example with 2 data series and 2 trendiness.
http://jsfiddle.net/ttwqazav/
I want to have only 1 trendline for both of them, as an average! Is that possible?
google.load('visualization', '1.1', {packages: ['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['X', 'Y', 'Z'],
[0, 0, 2],
[1, 2, 4],
[2, 4, 5],
[3, 6, 8],
[4, 8, 10],
[5, 10, 12],
[6, 12, 14],
[7, 14, 16],
[8, 16, 18],
[9, 18, 20],
[10, 20, 22]
]);
var options = {
height: 500,
legend: 'none',
colors: ['#9575cd', '#33ac71'],
pointShape: 'diamond',
trendlines: {
0: {
color:'red',
type: 'linear',
pointsVisible: false
}
}
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart'));
chart.draw(data, options);
}
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
Just specify data points as below:
var data = google.visualization.arrayToDataTable([
['X', 'Y'],
[0, 0],
[1, 2],
[2, 4],
[3, 6],
[4, 8],
[5, 10],
[6, 12],
[7, 14],
[8, 16],
[9, 18],
[10, 20],
[0, 2],
[1, 4],
[2, 5],
[3, 8],
[4, 10],
[5, 12],
[6, 14],
[7, 16],
[8, 18],
[9, 20],
[10, 22]
]);
But you cannot differentiate between the two sets of data points!
If your aim is to get average best fit line, it'll work. :)

use recursive function to generate combination in Swift

I have five arrays. I can use five for-loop to generate the result, but I need a recursive function so that I can generate the combinations from more arrays. How do I use a recursive function to generate the combinations? Each combination includes one element from the five arrays.
I'm not sure why you need it to be recursive, but there are a few ways to do it, anyway. You can use higher-order functions to make an Array extension that does what you want:
extension Array {
func everyOf<S: SequenceType where S.Generator.Element == T>(ar: S...) -> [[T]] {
return ar.reduce(self.map{[$0]}){
perms, items in perms.flatMap {
perm in Swift.map(items){ perm + [$0] }
}
}
}
}
This would work like:
[1, 2].everyOf([3, 4]) //[[1, 3], [1, 4], [2, 3], [2, 4]]
or:
[1, 2].everyOf([3, 4], [5, 6])
//[
// [1, 3, 5],
// [1, 3, 6],
// [1, 4, 5],
// [1, 4, 6],
// [2, 3, 5],
// [2, 3, 6],
// [2, 4, 5],
// [2, 4, 6]
//]
But the different arrays don't have to be the same length:
[1, 2].everyOf([3], [5, 6]) // [[1, 3, 5], [1, 3, 6], [2, 3, 5], [2, 3, 6]]
And you can do it as a non-method as well:
func everyOf<T>(ar: [[T]]) -> [[T]] {
return dropLast(ar).reduce(ar.last!.map{[$0]}){
perms, items in perms.flatMap{
perm in Swift.map(items){ perm + [$0] }
}
}
}
everyOf([[1, 2], [3, 4]]) // [[3, 1], [3, 2], [4, 1], [4, 2]]
If you're really into the 'aul recursion, though, here you go:
func everyOf<T>(seqs: [[T]]) -> [[T]] {
return last(seqs).map {
fSeq in everyOf(Array(dropLast(seqs))).flatMap {
seq in fSeq.map{ seq + [$0] }
}
} ?? [[]]
}
everyOf([[1, 2], [3, 4]]) // [[3, 1], [3, 2], [4, 1], [4, 2]]