-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Enumerable#index_with. #32523
Add Enumerable#index_with. #32523
Conversation
I've also needed this method on numerous occasions, but I named it index_to. What do you think of that name? Also, for the last code snippet, I think you meant |
I like it, 👍 |
Wanna to have this method in ruby too! 👍 |
8c02446
to
a17cb39
Compare
In the app I'm working on I've wished that index_by had a buddy that would assign the hash value instead of the key multiple times. Enter index_with. Useful when building a hash from a static list of symbols. Before you'd do: ```ruby POST_ATTRIBUTES.map { |attr_name| [ attr_name, public_send(attr_name) ] }.to_h ``` But now that's a little clearer and faster with: ````ruby POST_ATTRIBUTES.index_with { |attr_name| public_send(attr_name) } ``` It's also useful when you have an enumerable that should be converted to a hash, but you don't want to muddle the code up with the overhead that it takes to create that hash. So before, that's: ```ruby WEEKDAYS.each_with_object(Hash.new) do |day, intervals| intervals[day] = [ Interval.all_day ] end ``` And now it's just: ```ruby WEEKDAYS.index_with([ Interval.all_day ]) ``` It's also nice to quickly get a hash with either nil, [], or {} as the value.
a0c4128
to
429f15f
Compare
@jonathanhefner
I just noticed I'd forgotten to push that bit. Thanks! |
@kaspth Thank you for your response! Even though it's too late to change, I still want to defend my name choice. 😉 The connection between Also, to me, Either way, it's nice to have this in Rails. |
I'm with @jonathanhefner: If this goes to Ruby, I could imagine one of these method names being clearer:
|
I agree with @mcary, that |
- Clarify executor of `public_send`. - Do not wrap `Interval.all_day` into [] since an array is expected as a returned value. Related to rails#32523. [ci skip]
@jonathanhefner it's only too late once we've shipped Rails 6. At least I'm happy to keep going on this. I'm still not on board with the I can see how it sounds like a straight alias though. |
If this was the normal behaviour for [1,2,3].to_h # => {1 => 1, 2 => 2, 3 => 3} And the array of pairs behaviour was just a special case: [[:a, 1], [:b, 2]] # => { a: 1, b: 2} Then the hash = [1,2,3].to_h
hash.transform_values { |v| v * 2 } # => { 1 => 2, 2 => 4, 3 => 6 } Which I think is easier to understand. It would also then be just as simple to modify the keys rather than the values: hash.transform_keys { |k| (k + 96).chr.to_sym } # => {a: 1, b: 2, c: 3} Therefore perhaps a better solution is: class Array
def to_h
if all? {|i| i.kind_of?(Array) && i.length == 2}
super
else
map {|x| [x,x]}.to_h
end
end
end |
I've always had this named %w(one two three).expand(&:upcase)
=> {"one"=>"ONE", "two"=>"TWO", "three"=>"THREE"} Admittedly has no relation to any of the other proposals, but I find it far more intuitive than |
Careful, these are not equivalent:
The difference being the first constructs a new array instance for each value of the hash, while the second uses the same array instance for each value. If you mutate this value, like appending new Interval instance to one of the weekday arrays, then they will cause different results. (I've hit this bug before. 😅) In the first example, if assigned to intervals['Monday'] << Interval.new(1)
# intervals['Monday'] == [Interval.all_day, Interval.new(1)]
intervals['Tuesday'] << Interval.new(2)
intervals['Tuesday'] << Interval.new(3)
# intervals['Tuesday'] == [Interval.all_day, Interval.new(2), Interval.new(3)] But in the second case: intervals['Monday'] << Interval.new(1)
# intervals['Monday'] == [Interval.all_day, Interval.new(1)]
intervals['Tuesday'] << Interval.new(2)
intervals['Tuesday'] << Interval.new(3)
# intervals['Tuesday'] == [Interval.all_day, Interval.new(1), Interval.new(2), Interval.new(3)]
# but also:
# intervals['Monday'] == [Interval.all_day, Interval.new(1), Interval.new(2), Interval.new(3)]
# and every other value, too. It's the same difference as: Hash.new([Interval.all_day]) vs: Hash.new { [Interval.all_day] } and can be fixed the same way. It's just a buyer-beware gotcha. :-) |
In the app I'm working on I've wished that index_by had a buddy that would
assign the hash value instead of the key multiple times.
Enter index_with. Useful when building a hash from a static list of
symbols. Before you'd do:
But now that's a little clearer and faster with:
It's also useful when you have an enumerable that should be converted to a hash,
but you don't want to muddle the code up with the overhead that it takes to create
that hash. So before, that's:
And now it's just:
It's also nice to quickly get a hash with either nil, [], or {} as the value.