If I have an array: array = ["ruby", "code", "library"]. How can I move matched /^library$/ elements to the beginning. So array will look like this: array = ["library", "ruby", "code"]
4 Answers
it could be done in a number of ways. This is one
array = ["ruby", "code", "library"]
array.partition { |element| element.match /^library$/ }.flatten
1 Comment
Cary Swoveland
Enumerable#partition may preserve order, but the doc is mute on that.
Just out of curiosity:
[:select, :reject].map do |m|
["ruby", "code", "library"].public_send(m, &(/^library/.method(:=~)))
end.reduce :|
4 Comments
Sean
that is quite an interesting way to go about it. Nice thought exercise :)
Aleksei Matiushkin
@Sean Yeah, this is more about ruby-golf jokes, than about real code. But as an exercise it is fine. Please revise, I updated it.
Jordan Running
reduce :| made me laugh. Can we call that the "meh" operator?Aleksei Matiushkin
@Jordan Yes, I pity that there are no
:) and :] symbols permitted in Ruby :) “meh operator” is brilliant.def move_to_front(arr, pattern)
mi = matching_indices(arr, pattern)
return arr unless mi
a = arr.dup
mi.reverse_each.with_object([]) { |i,b| b.unshift(a.delete_at(i)) }.concat(a)
end
def matching_indices(arr, pattern)
arr.each_index.select do |i|
case pattern
when Regexp then arr[i] =~ pattern
when Proc then pattern[arr[i]]
else (arr[i] == pattern)
end
end
end
move_to_front ["ruby", "code", "library"], /\Alibrary\z/
#=> ["library", "ruby", "code"]
move_to_front ["ruby", "library", "code", "library"], "library"
#=> ["library", "library", "ruby", "code"]
move_to_front ["ruby", "libraries", "code", "library"], /librar(?:ies|y)/
#=> ["libraries", "library", "ruby", "code"]
move_to_front ["ruby", "libraries", "code", "library"], /\Alibrar/
#=> ["libraries", "library", "ruby", "code"]
move_to_front ["ruby", "libraries", "code", "library"],
->(str) { str =~ /librar(?:ies|y)/ }
#=> ["libraries", "library", "ruby", "code"]
move_to_front ("1".."9").to_a, /[13579]/
#=> ["1", "3", "5", "7", "9", "2", "4", "6", "8"]
move_to_front ("1".."9").to_a, ->(n) { n.to_i.odd? }
#=> ["1", "3", "5", "7", "9", "2", "4", "6", "8"]
move_to_front ("1".."9").to_a, ->(n) { false }
#=> ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
move_to_front ("1".."9").to_a, ->(n) { true }
#=> ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
Note:
matching_indices ["ruby", "libraries", "code", "library"], /librar(?:ies|y)/
#=> [1, 3]
The method move_to_front preserves the order of those elements that are moved and those that are not moved.
Comments
Three for one cent.
array.inject([]){|a,e| e[/^library/] ? a.unshift(e) : a<<e}
and
array & ["library"] | array
In case array contains the search element multiple times it becomes
array.find_all{ |e| e[/^library/] } + array.reject{ |e| e[/^library/] }
If you hate to use the array variable twice it can also like this
[array].map{|a| a & ["library"] | a}.flatten
The last one: using grep
array.grep(/library/) + array.grep( /^(?!library)/)
3 Comments
Jordan Running
The last one doesn't do what you think it does.
/[^library]/ will match any string that contains a character other than l, i, b, etc. Perhaps you meant /^(?!library)/?peter
@Jordan, I was aware of that and /^(?!library)/ would be better I suppose but the thing is: it works because it lets pass other strings and not "library"
Jordan Running
Sure, but it'll also match
"lliibbrraarryy" and "yrarbil".
array.sort { |str| str.match(/^library$/) ? 0 : 1 }