swift 4 combinations func - arrays

func combinations<T>(of array: [[T]]) -> [[T]] {
return array.reduce([[]]) { combihelper(a1: $0, a2: $1) }
}
func combihelper<T>(a1: [[T]], a2: [T]) -> [[T]] {
var x = [[T]]()
for elem1 in a1 {
for elem2 in a2 {
x.append(elem1 + [elem2])
}
}
return x
}
What's the best solution to write the code in one func and more swifty?

If all you want is to combine both methods into a single one just change a1 to $0 and a2 to $1:
func combinations<T>(of array: [[T]]) -> [[T]] {
return array.reduce([[]]) {
var x = [[T]]()
for elem1 in $0 {
for elem2 in $1 {
x.append(elem1 + [elem2])
}
}
return x
}
}
let multi = [[1,2,3,4,5],[1,2,3,4,5,6,7,8,9,0]]
combinations(of: multi) // [[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7], [1, 8], [1, 9], [1, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [2, 7], [2, 8], [2, 9], [2, 0], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6], [3, 7], [3, 8], [3, 9], [3, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [4, 7], [4, 8], [4, 9], [4, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [5, 9], [5, 0]]
Extending Collection, constraining the element to RangeReplaceableCollection and using higher-order functions we can came up with:
extension Collection where Element: RangeReplaceableCollection {
func combinations() -> [Element] {
reduce([.init()]) { result, element in
result.flatMap { elements in
element.map { elements + CollectionOfOne($0) }
}
}
}
}
let strings = ["12345","1234567890"]
strings.combinations() // ["11", "12", "13", "14", "15", "16", "17", "18", "19", "10", "21", "22", "23", "24", "25", "26", "27", "28", "29", "20", "31", "32", "33", "34", "35", "36", "37", "38", "39", "30", "41", "42", "43", "44", "45", "46", "47", "48", "49", "40", "51", "52", "53", "54", "55", "56", "57", "58", "59", "50"]

You could also do it without any for loops:
func combinations<T>(of array: [[T]]) -> [[T]]
{
return array.reduce([[]]){ c,a in c.flatMap{ e in a.map{e + [$0] } } }
}

Related

Array combinatorics

I am working in Ruby 2.7.
I have an Array, whose elements are one of three things: either a String or an Integer, or occasionally another Array with a pair of elements (this time, only Strings or Integers). There are no further levels of nesting for Arrays, by the definition of my problem.
Examples:
w = [1, 2, 'b', 4]
x = [[2, 'r'],[2, 'g']]
y = [[2, 'w']]
z = ['u', 6, [2, 'r']]
The context of the problem is that the inner arrays represent selectable alternatives for use in the outer array. I am looking for all possible ways to choose an element from each inner array, if present, and substitute that element into the outer array.
Examples:
f(w) = [ [1, 2, 'b', 4] ]
f(x) = [ [2, 2], [2, 'g'], ['r', 2], ['r', 'g'] ]
f(y) = [ [2], ['w'] ]
f(z) = [ ['u', 6, 2], ['u', 6, 'r'] ]
Order of elements in each selection (inner array of each solution) does not matter. Order of solutions in output also does not matter.
I can brute force an answer selecting/rejecting, transforming, and using Array#product; but I am looking for an approach that is as brief and elegant as possible.
The rules given in the question are unprecise and incomplete, so I've done my best to infer what they are.
Code
def doit(arr)
if arr.size == 1
e = arr.first
return e.is_a?(Array) ? (arr.map { |f| [f] }) : arr
end
(first, *rest), other = arr.partition { |e| e.is_a?(Array) }
return [arr] if first.nil?
prod = first.product(*rest)
return prod if other.empty?
prod.flat_map { |a| other.map { |e| [e, *a] } }
end
See Enumerable#partition, Array#product and Enumerable#flat_map.
Examples
doit [1, 2, 'b', 4]
#=> [[1, 2, "b", 4]]
doit [[2, 'r'],[2, 'g']]
#=> [[2, 2], [2, "g"], ["r", 2], ["r", "g"]]
doit [:a, [2, 'r'], :b, [2, 'g']]
#=> [[:a, 2, 2], [:b, 2, 2], [:a, 2, "g"], [:b, 2, "g"],
# [:a, "r", 2], [:b, "r", 2], [:a, "r", "g"], [:b, "r", "g"]]
doit [[2, 'w']]
#=> [[[2, "w"]]]
doit ['u', 6, [2, 'r']]
#=> [["u", 2], [6, 2], ["u", "r"], [6, "r"]]
doit [:a, [2, 3], :b, :c, [4, 5], :d, [6, 7]]
#=> [[:a, 2, 4, 6], [:b, 2, 4, 6], [:c, 2, 4, 6], [:d, 2, 4, 6],
# [:a, 2, 4, 7], [:b, 2, 4, 7], [:c, 2, 4, 7], [:d, 2, 4, 7],
# [:a, 2, 5, 6], [:b, 2, 5, 6], [:c, 2, 5, 6], [:d, 2, 5, 6],
# [:a, 2, 5, 7], [:b, 2, 5, 7], [:c, 2, 5, 7], [:d, 2, 5, 7],
# [:a, 3, 4, 6], [:b, 3, 4, 6], [:c, 3, 4, 6], [:d, 3, 4, 6],
# [:a, 3, 4, 7], [:b, 3, 4, 7], [:c, 3, 4, 7], [:d, 3, 4, 7],
# [:a, 3, 5, 6], [:b, 3, 5, 6], [:c, 3, 5, 6], [:d, 3, 5, 6],
# [:a, 3, 5, 7], [:b, 3, 5, 7], [:c, 3, 5, 7], [:d, 3, 5, 7]]
Note that the return value for doit [[2, 'w']] is different than that given in the question.
Explanation
The steps are as follows.
arr = [:a, [2, 'r'], :b, [2, 'g']]
(first, *rest), other = arr.partition { |e| e.is_a?(Array) }
#=> [[[2, "r"], [2, "g"]], [:a, :b]]
Ruby applies array decomposition to the above expression to obtain values for first, rest and other:
first
#=> [2, "r"]
rest
#=> [[2, "g"]]
other
#=> [:a, :b]
Continuing, because first.nil? #=> false in return [arr] if first.nil?, we do not return. Next:
prod = first.product(*rest)
#=> [[2, 2], [2, "g"], ["r", 2], ["r", "g"]]
other.empty? #=> false in return prod if other.empty? so we do not return.
I can best explain the remaining calculations by inserting puts statement in the code and running it.
prod.flat_map do |a|
puts "a = #{a}"
other.map do |e|
puts " e = :#{e}"
puts " [e, *a] = #{[e, *a]}"
[e, *a]
end
end
#=> [[:a, 2, 2], [:b, 2, 2], [:a, 2, "g"], [:b, 2, "g"],
# [:a, "r", 2], [:b, "r", 2], [:a, "r", "g"], [:b, "r", "g"]]
The following is displayed.
a = [2, 2]
e = :a
[e, *a] = [:a, 2, 2]
e = :b
[e, *a] = [:b, 2, 2]
a = [2, "g"]
e = :a
[e, *a] = [:a, 2, "g"]
e = :b
[e, *a] = [:b, 2, "g"]
a = ["r", 2]
e = :a
[e, *a] = [:a, "r", 2]
e = :b
[e, *a] = [:b, "r", 2]
a = ["r", "g"]
e = :a
[e, *a] = [:a, "r", "g"]
e = :b
[e, *a] = [:b, "r", "g"]

Transform array by cutting in half but extend elements

I want to transform an existing array to display it. Therefore I cut the array in half but add the content of the cut element to the remained elements.
# source structure
s = [[1, 'blue'],
[2, 'red'],
[3, 'yellow'],
[4, 'green'],
[5, 'orange'],
[6, 'black']]
# result structure
format_array(s)
# [[1, 'blue', 4, 'green'],
# [2, 'red', 5, 'orange'],
# [3, 'yellow', 6, 'black']]
How would you achieve it?
a = [[1, "blue"], [2, "red"], [3, "yellow"], [4, "green"], [5, "orange"], [6, "black"]]
first, last = a.first(a.size / 2), a.last(a.size / 2)
#=> [[[1, "blue"], [2, "red"], [3, "yellow"]], [[4, "green"], [5, "orange"], [6, "black"]]]
first.zip(last).map(&:flatten)
# [
# [1, "blue", 4, "green"],
# [2, "red", 5, "orange"],
# [3, "yellow", 6, "black"]
# ]
Just one more solution:
a.each_slice(a.size / 2).to_a.transpose.map(&:flatten)
#=> [[1, "blue", 4, "green"], [2, "red", 5, "orange"], [3, "yellow", 6, "black"]]
s.each_slice((s.size + 1) / 2).reduce(&:zip).map(&:flatten)
Step1: Divide array into two using each_slice method of array. each_slice documentation
Step2: Use array.zip method to map self with corresponding elements of array. zip documentation
Step3: Use flatten to flatten the array. Flatten documentation
s => [[1, "blue"], [2, "red"], [3, "yellow"], [4, "green"], [5, "orange"], [6, "black"]]
s1,s2 = s.each_slice((s.length)/2).to_a
==> [[[1, "blue"], [2, "red"], [3, "yellow"]], [[4, "green"], [5, "orange"], [6, "black"]]]
s1.zip(s2).map(&:flatten)
=> [[1, "blue", 4, "green"], [2, "red", 5, "orange"], [3, "yellow", 6, "black"]]
s = [[1, 'blue'], [2, 'red'], [3, 'yellow'], [4, 'green'], [5, 'orange'], [6, 'black']]
# Split into two sections
s1 = s[0...s.length/2]
s2 = s[s.length/2..-1]
# Compile
p s1.each_with_index.map { |x, i| x + s2[i] }
#[[1, "blue", 4, "green"], [2, "red", 5, "orange"], [3, "yellow", 6, "black"]]
a maths trick -))
s.group_by {|a| a[0]%((s.length)/2) }.values.map {|e| e.flatten }
# [
# [1, "blue", 4, "green"],
# [2, "red", 5, "orange"],
# [3, "yellow", 6, "black"]
# ]

Joining two ranges into 2d array Ruby

How do I join two ranges into a 2d array as such in ruby? Using zip doesn't provide the result I need.
(0..2) and (0..2)
# should become => [[0,0],[0,1],[0,2], [1,0],[1,1],[1,2], [2,0],[2,1],[2,2]]
Ruby has a built in method for this: repeated_permutation.
(0..2).to_a.repeated_permutation(2).to_a
I'm puzzled. Here it is a day after the question was posted and nobody has suggested the obvious: Array#product:
[*0..2].product [*1..3]
#=> [[0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3]]
range_a = (0..2)
range_b = (5..8)
def custom_join(a, b)
a.inject([]){|carry, a_val| carry += b.collect{|b_val| [a_val, b_val]}}
end
p custom_join(range_a, range_b)
Output:
[[0, 5], [0, 6], [0, 7], [0, 8], [1, 5], [1, 6], [1, 7], [1, 8], [2, 5], [2, 6], [2, 7], [2, 8]]
straight forward solution:
range_a = (0..2)
range_b = (5..8)
def custom_join(a, b)
[].tap{|result| a.map{|i| b.map{|j| result << [i, j]; } } }
end
p custom_join(range_a, range_b)
Output:
[[0, 5], [0, 6], [0, 7], [0, 8], [1, 5], [1, 6], [1, 7], [1, 8], [2, 5], [2, 6], [2, 7], [2, 8]]
Simply, this will do it:
a = (0...2).to_a
b = (0..2).to_a
result = []
a.each { |ae| b.each { |be| result << [ae, be] } }
p result
# => [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]

Combinaison ruby Array multidimensionnel to get a Array two dimensional

I have a Array multidimensionnel like:
[[1, 1, 4], [2],[2, 3]]
How to get a combinaison each element except the combinaison in the same array: [1, 1],[1, 4],[2, 3]
I want to get:
[1, 2],[1, 3],[4, 2],[4, 3],[2, 3]
Thanks.
Short answer is:
[[1, 1, 4], [2],[2, 3]].combination(2).flat_map {|x,y| x.product(y)}.uniq
# => [[1, 2], [4, 2], [1, 3], [4, 3], [2, 2], [2, 3]]
Step by step
step1 = [[1, 1, 4], [2],[2, 3]].combination(2)
# => [[[1, 1, 4], [2]], [[1, 1, 4], [2, 3]], [[2], [2, 3]]]
step2 = step1.flat_map {|x,y| x.product(y)}
# => [[1, 2], [1, 2], [4, 2], [1, 2], [1, 3], [1, 2], [1, 3], [4, 2], [4, 3], [2, 2], [2, 3]]
result = step2.uniq
# => [[1, 2], [4, 2], [1, 3], [4, 3], [2, 2], [2, 3]]
Update
For full uniqueness you could use:
[[1, 1, 4], [2],[2, 3, 4]].combination(2).flat_map {|x,y| x.product(y)}.map(&:sort).uniq
arr = [[1, 1, 4], [2], [2, 3]]
a = arr.map(&:uniq)
(arr.size-1).times.flat_map { |i| arr[i].product(arr[i+1..-1].flatten.uniq)}.uniq
#=> [[1,2],[1,3],[4,2],[4,3],[2,2],[2,3]]
Here's another way that uses the method Array#difference that I defined here:
arr.flatten.combination(2).to_a.difference(arr.flat_map { |a| a.combination(2).to_a }).uniq
Array#difference is similar to Array#-. The difference is illustrated in the following example:
a = [1,2,3,4,3,2,2,4]
b = [2,3,4,4,4]
a - b #=> [1]
a.difference b #=> [1, 3, 2, 2]

angularjs nvd3-line-chart set y2 axis

I use nvd3-line-chart angularjs directive.
My data is:
$scope.exampleData = [
{
"key": "Series 1",
"values": [ [1, 2], [2, 10], [3, 6], [4, 15], [5, 8] ]
},
{
"key": "Series 2",
"values": [ [1, 5], [2, 30], [3, 8], [4, 11], [5, 4] ]
},
{
"key": "Series 3",
"values": [ [1, 2000], [2, 10000], [3, 600], [4, 1500], [5, 8000] ]
}
]
Html:
nvd3-line-chart(
data="exampleData"
id="graph-Data-1"
width="1170"
height="494"
showXAxis="true"
showYAxis="true"
tooltips="true"
useInteractiveGuideline="true"
showLegend="true"
ng-if="exampleData"
)
How i can assign Y2 to Series 3 data? I found line-plus-bar-chart directive but how can i implement this via nvd3-line-chart directive?
I'm afraid you can't use your data to render a secondary axis. It is out of the scope of the data itself.
The best thing you could do is to trick it yourself: http://www.d3noob.org/2013/01/using-multiple-axes-for-d3js-graph.html

Resources