简体   繁体   中英

ruby sorting array - moving matched elements to the beginning

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"]

it could be done in a number of ways. This is one

array = ["ruby", "code", "library"]
array.partition { |element| element.match /^library$/ }.flatten

Just out of curiosity:

[:select, :reject].map do |m|
  ["ruby", "code", "library"].public_send(m, &(/^library/.method(:=~)))
end.reduce :| 
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.

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)/)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM