Array method versus hashes - arrays

I have an object (returned from and API) that is either a hash or an array of hashes. I want to enclose it in an array if it is not already an array.
I tried to apply Array on it, which functions in an expected way with numbers or arrays:
Array(1) # => [1]
Array([1, 2]) # => [1, 2]
Array([{a: 1}, {b: 2}]) # => [{:a=>1}, {:b=>2}]
but it fails with hashes:
Array({a: 1}) # => [[:a, 1]]
which should be [{:a=>1}].
Alternatively, I could add a type check:
responses = [responses] if responses.is_a?(Hash)
Is there a better solution?

ActiveSupport introduces Array#wrap that does exactly what you want:
Array.wrap(responses)
I personally prefer to never use any Rails helpers for many reasons, so I would stick with [responses].flatten, or, even better, with the most explicit version:
case responses
when Hash then [responses]
when Array then responses
else raise "shit happened"
end

As #mudasobwa suggested, [responses].flatten is perhaps the cleanest solution:
[{a: 1}].flatten #=> [{:a=>1}]
[[{a: 1}, {b: 2}]].flatten #=> [{:a=>1}, {:b=>2}]
Clearly this inconsistent response format is not a great API design; but that's unfortunately the nature of working with external resources...
If each hash in the above array does represent a unique object, then I would leave that code as-is. However, if you actually have a different hash for each attribute of a single entity (?!), then you could further clean up the API response as follows:
[{a: 1}].flatten.reduce(:merge) #=> {:a=>1}
[[{a: 1}, {b: 2}]].flatten.reduce(:merge) #=> {:a=>1, :b=>2}

I want to enclose it in an array if it is not already an array.
What about:
result = [result] unless result.is_a? Array
Alternatively, using try_convert:
result = Array.try_convert(result) || [result]

Related

How do I change the functionality of the built in Array class in Ruby?

I am writing code in Ruby.
Say I have an array like this:
myarray = [1,2,3,4,5]
I want to change the code of the Array class so that myarray[7] would return "out of bounds" instead of nil.
I don't want to make so that I check if something is out of bounds and then return "out of bounds", I want to implement this in Array directly.
Is this possible? Do I have to extend the Array class?
I'm Not sure how to start, very new to ruby. My initial thoughts were overriding a method in the Array class, but I'm not sure how to do that when I don't know what method is being used in myarray[i].
Suppose
arr = [1,2,3,4,5]
Let's start by examining the doc Array#[]. As seen, that method can have a single integer argument:
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> nil
arr[-7] #=> nil
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have two integer arguments:
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have a range of integers as an argument:
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
As I understand, you wish to alter Array#[] in such way that its behavior is unchanged except for the case when its argument is a single integer representing an offset into the array that is out-of-bounds.1. That could be done by writing the method in a module and then prepend that module to the class Array with the method Module#prepend.
module NewSlice
def [](*args)
arg1, arg2 = args
if arg2.nil? && arg1.is_a?(Integer) &&
(arg1 > self.size-1 || arg1 < -self.size)
"out of range"
else
super
end
end
end
Array.prepend(NewSlice)
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
We see that
Array.ancestors
#=> [NewSlice, Array, Enumerable, Object, Kernel, BasicObject]
showing that super in NewSlice#[] calls the original method Array#[] after NewSlice has been prepended to Array. Since super has no arguments all the arguments that were passed to the new Array#[] method ( defined in NewSlice) are passed to the original Array#[].
Aliases were commonly used in Ruby prior to the introduction of Module#prepend in Ruby v2.0. They are still used but their importance has diminished greatly since prepend has become available.
If nil is to be replaced by "out of bounds" in all cases where Array#[] returns nil, write
module NewSlice
def [](*args)
super || "out of bounds"
end
end
Array.prepend(NewSlice)
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr[7,4] #=> "out of range"
arr[7..10] #=> "out of range"
1. Whether it is advisable to modify core methods such as Array#[] is a separate question, but it can result in pain and suffering.
TL;DR
This is an interesting question about how to monkeypatch core Ruby classes like Array. However, I'd be remiss if I didn't point out that it involves some hijinks that seem unnecessary, since you could get the same behavior with a simple logical OR operator like:
[1, 2, 3][5] || 'out of bounds'
#=> "out of bounds"
Still, if you want to change the behavior of a core class then it can certainly be done.
Re-Open the Core Class
In Ruby, almost everything that isn't a keyword is a method. Pragmatically, Array::[] is really just a method for indexing into an array object, with a little syntactic sugar from the interpreter to allow its arguments to be placed inside the brackets. Because it's just an instance method defined by the Array class, it can be modified in various ways such as re-opening the core class to modify the method, or by creating a singleton method on the instance. The first is conceptually simpler, but singleton methods are probably the safest solution for real-world programming.
You can re-open the Array class and redefine Array::[] as follows:
class Array
# save off a copy of the existing method; we still need it
alias_method :'old_[]', :'[]' unless defined? Array::old_[]
# pass all arguments to the old method, but return a string
# when the result is falsey
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
You can then demonstrate that it works like a regular Array, but with your expected behavior:
a = [10, 20, 30]
a[0] #=> 10
a[0,2] #=> [10, 20]
a[100] #=> "out of bounds"
Add a Singleton Method
While the code above works, it's just generally a bad idea to monkeypatch a core class like Array. If you don't want to encapsulate this behavior in a subclass (e.g. class MyArray < Array), then you should use refinements (using Module#refine) or singleton methods like the following to reduce the scope of your changes. For example:
a = [10, 20, 30]
class << a
alias_method :'old_[]', :'[]' unless self.respond_to? 'old_[]'
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
By limiting the scope of our change to a single instance, we're much less likely to cause serious or unrecoverable problems with core classes. A lot of things can go wrong in a Ruby program if a core class like Array starts returning truthy values (e.g. a String value such as out of bounds) rather than a falsey value like nil, so caveat emptor!
If you really want to break existing code (standard classes and ruin even methods of the current Array class itself, which rely on the current behaviour), you can of course monkeypatch it - open it and redefine the method in any way you like, as has been outlined in various answers to this question.
A more sane approach would be to subclass Array, i.e.
class BoundCheckingArray < Array
# redefined the methods according to your taste.
end
Of course this would violate the Liskov Substitution Principle.
Another approach will be to define a complete separate class and use Delegator to avoid rewriting everything from scratch, by delegating methods you did not rewrite explicitly, to the underlying array.
In both cases you need to be aware, that those methods in your BoundCheckingArray, which you did not explicitly rewrite and hence are taken from BoundCheckingArray, will stop working, if they assume that they can safely access the array outside of the bounds.
Another possibility would be to not modify existing Array methods, but simply add bound checking setters and getters, i.e. with monkeypatching:
class Array
def at_checked(i)
fail "out_of_bounds" if i >= size || i < -size
at(i)
end
def set_checked(i, new_value)
# analoguous
end
end
Of course this approach would also work with subclassing (now adhering to Liskov's principle, because you just added methods) and delegating. Note that I coped explicitly with negative index values, assuming that you would like to use this feature in your bound checking array too.
You may know classes in Ruby are defined like:
class Foo
def foo
'foo'
end
end
Foo.new.foo # calls instance method `foo` on the instance of `Foo`
# => 'foo'
Classes and modules in Ruby can be "reopened" for re-definition (although it's a bit frowned upon -- makes it difficult to track code b/c code can be in either/any place):
class Foo
def bar
'bar'
end
def foo
'overwrite foo'
end
end
f = Foo.new
f.bar
# => 'bar'
f.foo
# => 'overwrite foo'
This means you can also do:
class Array
# re-define anything you want
end
# alternatively:
Array.class_eval do
# the same as the above, in most ways
end
Even though it's even less recommended to modify existing methods of core Ruby classes. Not only does it break assumptions other Ruby developers may have of the code (i.e. misleading code), its global effect will likely break behaviors in other libraries, etc.

Ruby Split array for two with partition and with_index

Can you give explanation of logic or algorithm of ruby behaviour for this construction:
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
How to formalize logic when iterate through Enumerable give 2 arrays output.
When we just call single partition its clear - just method behavior, but when it trails by with_index this construction become "Magical" for me.
Thank you
UPD: The condition is not in block of partition, it is in separate 'Enumerable' Object method block. This method is with_index. This second level of interaction is interesting for me. Why do conditions of with_index have influence on partition result? This is a behavior that is not clear from partition documentation.
You've probably read in the Ruby docs for partition:
If no block is given, an enumerator is returned instead.
> arr = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
> arr.partition
=> #<Enumerator: ...>
You'll see the same thing in the description for a lot of the methods in Enumerable but there isn't much detail about the enumerator that's returned.
The key to the enumerator chaining is in the the behaviour of the each method in the Enumerator that's returned. For example, the Enumerator returned by partition has an each method that behaves like partition. This is how you're able to pass a single block and get the combined behaviour of partition and with_index. If you do this in a couple of steps it might help:
> enumerator = arr.partition
=> #<Enumerator: ...>
> enumerator.each { |n| n < 3 } # just to demonstrate `each` performing a partition
=> [[1, 2], [3, 4, 5]]
> enumerator.with_index { |_, index| index > 2 }
=> [[4, 5], [1, 2, 3]]
Another way to think about it is that partition with no block given is like passing :partition to enum_for e.g.
> another_enum = arr.enum_for(:partition)
=> #<Enumerator: ...>
> another_enum.with_index { |_, index| index > 2 } # same result as above
=> [[4, 5], [1, 2, 3]]
When the index is > 2 ruby create a new array with the rest of values
partition
Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.
If no block is given, an enumerator is returned instead.
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
=> [[4, 5], [1, 2, 3]]
First array will contains [4,5] because it satisfys the condition index > 2.
Second array will contains all other elements: [1,2,3]
You are conflating the Enumerable module and the Enumerator class. All methods in the module Enumerable are instance methods that require their receiver to be an enumerator (an instance of the class Enumerator).
You use "include Enumerable" in your custom class and implement an each method which returns an enumerator:
def each
return enum_for(:each) unless block_given?
#apples.each { |apple| yield apple }
end
When a method contained in Enumerable is executed on an instance of a class that includes Enumerable, Ruby inserts the method each IMPLICITLY between the instance and the Enumerable method.
with_index is NOT a method of Enumerable module. It is an instance method of the Enumerator class. Now remember I stated that when you include Enumerable module in your custom class and implement an each method, that each method can be used to return an enumerator instance. So, classes that have a method each that returns an enumerator can make use of the method Enumerator#with_index by (explicitly) inserting each between an instance of the class and with_index. Or it can invoke with_index on the enumerable module method since that returns an enumerator instance:
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
In the above example, partition is an instance method of Enumerable module and with_index is an instance method of Enumerator class. partition returns an enumerator instance which can take with_index.
Now for understanding what this statement does, you can simply look at the Enumerable docs which explains what partition does:
Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.
So in your case, it is determining whether the index is greater than 2. If it is, it gets put in one array, otherwise the other.

collect all elements and indices of an array in two separate arrays in Ruby

Suppose I have an array array = [1,2,3,4,5]
I want to collect all the elements and indices of the array in 2 separate arrays like
[[1,2,3,4,5], [0,1,2,3,4]]
How do I do this using a single Ruby collect statement?
I am trying to do it using this code
array.each_with_index.collect do |v,k|
# code
end
What should go in the code section to get the desired output?
Or even simpler:
[array, array.each_index.to_a]
I like the first answer that was posted a while ago. Don't know why the guy deleted it.
array.each_with_index.collect { |value, index| [value,index] }.transpose
Actually I am using an custom vector class on which I am calling the each_with_index method.
Here's one simple way:
array = [1,2,3,4,5]
indexes = *array.size.times
p [ array, indexes ]
# => [[1, 2, 3, 4, 5], [0, 1, 2, 3, 4]]
See it on repl.it: https://repl.it/FmWg

Ruby : Choosing between each, map, inject, each_with_index and each_with_object

When I started writing Ruby many years ago, it took me a while to understand the difference between each and map. It only got worse when I discovered all the other Enumerable and Array methods.
With the help of the official documentation and many StackOverflow questions, I slowly began to understand what those methods did.
Here is what took me even longer to understand though :
Why should I use one method or another?
Are there any guidelines?
I hope this question isn't a duplicate : I'm more interested in the "Why?" than the "What?" or "How?", and I think it could help Ruby newcomers.
A more tl;dr answer:
How to choose between each, map, inject, each_with_index and each_with_object?
Use #each when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:
numbers.each { |number| puts number.abs }
Use #map when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:
numbers.map { |number| number ** 2 }
Use #inject when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:
numbers.inject(&:+)
Use #each_with_index in the same situation as #each, except you also want the index with each element:
numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
Uses for #each_with_object are more limited. The most common case is if you need something similar to #inject, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):
numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }
Which object can I use?
First, the object you're working with should be an Array, a Hash, a Set, a Range or any other object that respond to each. If it doesn't, it might be converted to something that will. You cannot call each directly on a String for example, because you need to specify if you'd like to iterate over each byte, character or line.
"Hello World".respond_to?(:each)
#=> false
"Hello World".each_char.respond_to?(:each)
#=> true
I want to calculate something with each element, just like with a for loop in C or Java.
If you want to iterate over each element, do something with it and not modify the original object, you can use each. Please keep reading though, in order to know if you really should.
array = [1,2,3]
#NOTE: i is a bound variable, it could be replaced by anything else (x, n, element). It's a good idea to use a descriptive name if you can
array.each do |i|
puts "La"*i
end
#=> La
# LaLa
# LaLaLa
It is the most generic iteration method, and you could write any of the other mentioned methods with it. We will actually, for pedagogical purposes only. If you spot a similar pattern in your code, you could probably replace it with the corresponding method.
It is basically never wrong to use each, it is almost never the best choice though. It is verbose and not Ruby-ish.
Note that each returns the original object, but this is rarely (never?) used. The logic happens inside the block, and should not modify the original object.
The only time I use each is:
when no other method would do. The more I learn about Ruby, the less often it happens.
when I write a script for someone who doesn't know Ruby, has some programming experience (e.g. C, Fortran, VBA) and would like to understand my code.
I want to get an Array out of my String/Hash/Set/File/Range/ActiveRecord::Relation
Just call object.to_a.
(1..10).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"Hello world".each_char.to_a
#=> ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
{:a => 1, :b => 2}.to_a
#=> [[:a, 1], [:b, 2]]
Movie.all.to_a #NOTE: Probably very inefficient. Try to keep an ActiveRecord::Relation as Relation for as long as possible.
#=> [Citizen Kane, Trois couleurs: Rouge, The Grapes of Wrath, ....
Some methods described below (e.g. compact, uniq) are only defined for Arrays.
I want to get a modified Array based on the original object.
If you want to get an Array based on the original object, you can use map. The returned object will have the same size as the original one.
array = [1,2,3]
new_array = array.map do |i|
i**2
end
new_array
#=> [1, 4, 9]
#NOTE: map is often used in conjunction with other methods. Here is the corresponding one-liner, without creating a new variable :
array.map{|i| i**2}
#=> [1, 4, 9]
# EACH-equivalent (For pedagogical purposes only):
new_array = []
array.each do |i|
new_array << i**2
end
new_array
#=> [1, 4, 9]
The returned Array will not replace the original object.
This method is very widely used. It should be the first one you learn after each.
collect is a synonym of map. Make sure to use only one of both in your projects.
I want to get a modified Hash based on the original Hash.
If your original object is a Hash, map will return an Array anyway. If you want a Hash back :
hash = {a: 1, b: 2}
hash.map{|key, value| [key, value*2]}.to_h
#=> {:a=>2, :b=>4}
# EACH-equivalent
hash = {a: 1, b: 2}
new_hash = {}
hash.each do |key,value|
new_hash[key]=value*2
end
new_hash
#=> {:a=>2, :b=>4}
I want to filter some elements.
I want to remove nil elements
You can call compact. It will return a new Array without the nil elements.
array = [1,2,nil,4,5]
#NOTE: array.map{|i| i*2} Would raise a NoMethodError
array.compact
# => [1, 2, 4, 5]
# EACH-equivalent
new_array = []
array.each do |integer_or_nil|
new_array << integer_or_nil unless integer_or_nil.nil?
end
new_array
I want to write some logic to determine if an element should be kept in the new Array
You can use select or reject.
integers = (1..10)
integers.select{|i| i.even?}
# => [2, 4, 6, 8, 10]
integers.reject{|i| i.odd?}
# => [2, 4, 6, 8, 10]
# EACH-equivalent
new_array = []
integers.each do |i|
new_array << i if i.even?
end
new_array
I want to remove duplicate elements from your Array
You can use uniq :
letters = %w(a b a b c)
letters.uniq
#=> ["a", "b", "c"]
# EACH-equivalent
uniq_letters = []
letters.each do |letter|
uniq_letters << letter unless uniq_letters.include?(letter)
end
uniq_letters
#TODO: Add find/detect/any?/all?/count
#TODO: Add group_by/sort/sort_by
I want to iterate over all the elements while counting from 0 to n-1
You can use each_with_index :
letters = %w(a b c)
letters.each_with_index do |letter, i|
puts "Letter ##{i} : #{letter}"
end
#=> Letter #0 : a
# Letter #1 : b
# Letter #2 : c
#NOTE: There's a nice Ruby syntax if you want to use each_with_index with a Hash
hash = {:a=>1, :b=>2}
hash.each_with_index{|(key,value),i| puts "#{i} : #{key}->#{value}"}
# => 0 : a->1
# 1 : b->2
# EACH-equivalent
i = 0
letters.each do |letter|
puts "Letter ##{i} : #{letter}"
i+=1
end
each_with_index returns the original object.
I want to iterate over all the elements while setting a variable during each iteration and using it in the next iteration.
You can use inject :
gauss = (1..100)
gauss.inject{|sum, i| sum+i}
#=> 5050
#NOTE: You can specify a starting value with gauss.inject(0){|sum, i| sum+i}
# EACH-equivalent
sum = 0
gauss.each do |i|
sum = sum + i
end
puts sum
It returns the variable as defined by the last iteration.
reduce is a synonym. As with map/collect, choose one keyword and keep it.
I want to iterate over all the elements while keeping a variable available to each iteration.
You can use each_with_object :
letter_ids = (1..26)
letter_ids.each_with_object({}){|i,alphabet| alphabet[("a".ord+i-1).chr]=i}
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12, "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18, "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
# EACH-equivalent
alphabet = {}
letter_ids.each do |i|
letter = ("a".ord+i-1).chr
alphabet[letter]=i
end
alphabet
It returns the variable as modified by the last iteration. Note that the order of the two block variables is reversed compared to inject.
If your variable is a Hash, you should probably prefer this method to inject, because h["a"]=1 returns 1, and it would require one more line in your inject block to return a Hash.
I want something that hasn't been mentioned yet.
Then it's probably okay to use each ;)
Notes :
It's a work in progress, and I would gladly appreciate any feedback. If it's interesting enough and fit in one page, I might extract a flowchart out of it.

Flatten all values of multiple arrays in Swift

I have a Dictionary of Integer Arrays like below:
let numbers = [1: [2, 3], 4: [5, 6, 7], 8: [9]]
What I really want is a single flattened Array of all of the values (which themselves are arrays), like so:
[2, 3, 5, 6, 7, 9]
Now, I have been able to call numbers.values.array to get:
[[2, 3], [5, 6, 7], [9]]
But what I'm looking for is to merge these one step further, flattening them.
Does Swift (1.1, or 1.2) offer a convenience method for this?
With a combination of numbers.values.array and a reduce function you can simplify this down in one line of code.
numbers.values.array.reduce([], combine: +) // [5,6,7,2,3,9]
However, I would like to note that since you are using a dictionary, you cannot guarantee that the values will be sorted, so you can use the sorted function to accomplish this:
sorted(numbers.values.array.reduce([], combine: +), <) // [2,3,5,6,7,9]
As #Jeffery Thomas stated, you can also use flatmap which was just added in Swift 1.2:
sorted(numbers.values.array.flatMap { $0 }, <)
And to take it a step further, using the global sorted function, the < is extraneous because it is the default and using the global reduce and flatMap functions, you can remove the array property as pointed out by Martin R, so it can be reduced down to:
sorted(reduce(numbers.values, [], +))
sorted(flatMap(numbers.values) { $0 })
Another possible solution is
[].join(numbers.values)
And if you want the values in the order corresponding to the sorted
dictionary keys then it would be
flatMap(sorted(numbers.keys)) { numbers[$0]! }
This is called flattening, and it's a relatively common operation. There are a number of ways to do it, so pick one that suits your needs.
numbers.values.array.reduce([], combine: +) // As stated by #Bluehound
reduce(numbers.values, [], +)
numbers.values.array.flatMap { $0 } // Swift 1.2 (Xcode 6.3)
flatMap(numbers.values) { $0 } // Swift 1.2 (Xcode 6.3)
flatMap may be the most useful, if the next step after flattening is mapping.
NOTE: Thanks #MartinR for the syntax tip.

Resources