Suppose I have
an_array = [[2, 3], [1, 4], [1, 3], [2, 1], [1, 2]]
I want to sort this array by the first value of each inner array, and then by the second (so the sorted array should look like this: [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3]])
What's the most readable way to do this?
This is the default behavior for sorting arrays (see the Array#<=> method definition for proof). You should just be able to do:
an_array.sort
If you want some non-default behaviour, investigate sort_by (ruby 1.8.7+)
e.g. sort by the second element then by the first
a.sort_by {|e| [e[1], e[0]]} # => [[2, 1], [1, 2], [1, 3], [2, 3], [1, 4]]
or sort by the first element ascending and then the second element descending
a.sort_by {|e| [e[0], -e[1]]} # => [[1, 4], [1, 3], [1, 2], [2, 3], [2, 1]]
an_array.sort
Related
I have four 2d arrays of varying lengths. Is there a way to compare them to make sure none of the arrays share a value? Is there a simple way to code it or a gem I could use?
To back my question up with an example:
array1 = [[2,3],[2,4]]
array2 = [[1,3],[2,3],[3,3]]
array3 = [[5,3],[6,3],[7,3],[8,3],[9,3]]
I want a checker that would let me know that array1 and array2 have an element the same.
Is this doable?
You might do it as follows.
Code
def shared_values?(*arr)
a = arr.map(&:uniq).reduce(:+)
a.size > a.uniq.size
end
Examples
array1 = [[2, 3], [2, 4]]
array2 = [[1, 3], [2, 3], [3, 3]]
array3 = [[5, 3], [6, 3], [7, 3],[8, 3],[9, 3]]
shared_values? array1, array2, array3 #=> true
array1 = [[2, 4]]
shared_values? array1, array2, array3 #=> false
array1 = [[2, 4], [2, 4]]
shared_values? array1, array2, array3 #=> false
array1 = [[2, 3], [2, 4], [2, 4]]
shared_values? array1, array2, array3 #=> false
Explanation
For the last example above:
arr = [array1, array2, array3]
#=> [ [[2, 3], [2, 4], [2, 4]],
# [[1, 3], [2, 3], [3, 3]],
# [[5, 3], [6, 3], [7, 3], [8, 3], [9, 3]] ]
a = arr.map(&:uniq)
#=> [ [[2, 3], [2 ,4]],
# [[1, 3], [2, 3], [3, 3]],
# [[5, 3], [6, 3], [7, 3], [8, 3], [9, 3]] ]
b = a.reduce(:+)
#=> [[2, 3], [2, 4], [1, 3], [2, 3], [3, 3],
# [5, 3], [6, 3], [7, 3], [8, 3], [9, 3]]
c = b.uniq
#=> [[2, 3], [2, 4], [1, 3], [3, 3],
# [5, 3], [6, 3], [7, 3], [8, 3], [9, 3]]
b.size > c.size
# 10 > 9 #=> true
arr.map(&:uniq) is the same as:
arr.map { |a| a.uniq }
a.reduce(:+) uses the form of Enumerable#reduce that takes an argument that is a symbol, naming a method to be applied to each element of arr, the result being the sum of the three arrays that comprise the elements of b.
If the arrays are in a consistent format, like all numbers and not a mix of floating point and strings, you can do this:
array1 & array2
# => [[2, 3]]
That means to test if they overlap:
(array1 & array2).any?
If you can be assured each of the elements in all of the arrays are unique, then you can test quickly if there are any duplicates:
sum = array1 + array2 + array3 + array4
sum.length == sum.uniq.length
If each array may contain duplicates then you'd need to pair them off and compare A vs. B for all possible pairs.
Why do we see such difference below? Why exactly such array?
enum = [1,2].lazy.flat_map{[[3,4],[5,6]]}.with_index
enum.to_a.map(&:first)
# => [[3, 4], [5, 6], [3, 4], [5, 6]]
enum.map(&:first).to_a
# => [[], [5], [3, 4], [5, 6]]
The reason this happens has nothing to do with lazy - it has something to do with the subtleties of map(&:...).
The first option (enum.to_a.map(&:first)) translates to:
enum.to_a.map { |x| x.first }
# => [[3, 4], [5, 6], [3, 4], [5, 6]]
when x is [[3,4], 0], then [[5,6], 1]...
The second option, one the other hand translates to:
enum.map { |x, i| x.first(i) }
# => [[], [5], [3, 4], [5, 6]]
which brings the first i item for each x array (since the arrays in our example have only 2 elements, x.first(3) still returns two elements...).
The same would happen without lazy:
enum2 = [1,2].flat_map{[[3,4],[5,6]]}.to_enum.with_index
What to_a does in this case is takes the two parameters of each item in the enumeration, and turns them to a single array item.
I have a string with an array of arrays inside:
"[[1, 2], [3, 4], [5, 6]]"
Can I convert this to the array of arrays, without using eval or a regular expression, gsub, etc.?
Can I make turn it into:
[[1, 2], [3, 4], [5, 6]]
How about the following?
require 'json'
arr = JSON.parse("[[1, 2], [3, 4], [5, 6]]") # => [[1, 2], [3, 4], [5, 6]]
arr[0] # => [1, 2]
The same can be done using Ruby standard libaray documentation - YAML:
require 'yaml'
YAML.load("[[1, 2], [3, 4], [5, 6]]")
# => [[1, 2], [3, 4], [5, 6]]
Is there a simple way to create pairs from an array?
For example, if I have an array [1,2,3,4] how would I go about trying to return this array?
[[1,2], [1,3], [1,4], [2,1], [2,3], [2,4], [3,1], [3,2], [3,4], [4,1], [4,2], [4,3]]
Every element is paired with every other other element except itself, and duplicates are allowed.
You can use Array#permutation for this:
[1,2,3,4].permutation(2).to_a
# => [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]]
[1,2,3,4].permutation(2).map{ |n| "(#{ n.join(",") })" }
# => ["(1,2)", "(1,3)", "(1,4)", "(2,1)", "(2,3)", "(2,4)", "(3,1)", "(3,2)", "(3,4)", "(4,1)", "(4,2)", "(4,3)"]
I have the following multi-dimensional array in Ruby:
[[1,2], [3], [4,5,6]]
I need to have the following output:
[[1,3,4], [1,3,5], [1,3,6], [2,3,4], [2,3,5], [2,3,6]]
I have tried creating a recursive function, but I'm not having much luck.
Are there any Ruby functions that would help with this? Or is the only option to do it recursively?
Thanks
Yup, Array#product does just that (Cartesian product):
a = [[1,2], [3], [4,5,6]]
head, *rest = a # head = [1,2], rest = [[3], [4,5,6]]
head.product(*rest)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]
Another variant:
a.inject(&:product).map(&:flatten)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]