2015-04-16 1 views
4

У меня есть текстовый массив.Как вы можете отсортировать массив в Ruby, начиная с определенной буквы, например, буквой f?

text_array = ["bob", "alice", "dave", "carol", "frank", "eve", "jordan", "isaac", "harry", "george"] 

text_array = text_array.sort даст нам отсортированный массив.

Однако, я хочу отсортированный массив с f в качестве первой буквы для нашего заказа, а e - как последний.

Таким образом, конечный результат должен быть ...

text_array = ["frank", "george", "harry", "isaac", "jordan", "alice", "bob", "carol", "dave", "eve"] 

Что бы быть лучшим способом для достижения этой цели?

ответ

3

Я думаю, что проще всего было бы, чтобы повернуть отсортированный массив:

text_array.rotate(offset) if offset = text_array.find_index { |e| e.size > 0 and e[0] == 'f' } 
+0

Не должно '[" ab "," af "]' sorted be '[" af "," ab "]'? –

+0

@CarySwoveland Не знаю. Должно ли это? – Gumbo

+0

Крис, вы хотите сортировать буквы после первого, когда первая буква из двух слов одинакова? –

4

Попробуйте это:

result = (text_array.select{ |v| v =~ /^[f-z]/ }.sort + text_array.select{ |v| v =~ /^[a-e]/ }.sort).flatten 

Это не самый красивый, но это будет получить работу.

Редактировать в комментарий. Создание более общий кусок кода:

before = [] 
after = [] 
text_array.sort.each do |t| 
    if t > term 
    after << t 
    else 
    before << t 
    end 
end 
return (after + before).flatten 

Этот код предполагает, что term является то, что вы хотите, чтобы разделить массив. И если значение массива равно term, оно будет в конце.

+0

Спасибо, это здорово. Что, если я хотел бы получить более конкретную информацию. Вместо того, чтобы начинать с «f». Я хочу начать с «причуды». «fad-z» является первым, а затем «a-fad» следующим? –

+0

@chrisP Добавлен новый, более общий код. –

+1

Вы также можете использовать 'text_array.sort.each do | t |' вместо 'text_array.each do | t |', поэтому вам не нужно делать 'before.sort' и' after.sort' – Sid

1

Объединяя ответ Райан Д.К. и мой предыдущий ответ, это один вкладыш можно использовать без каких-либо регулярных выражений:

text_array = text_array.sort!.select {|x| x.first >= "f"} + text_array.select {|x| x.first < "f"} 
3

Вы можете сделать это с помощью хэш:

alpha = ('a'..'z').to_a 
    #=> ["a", "b", "c",..."x", "y", "z"] 
reordered = alpha.rotate(5) 
    #=> ["f", "g",..."z", "a",...,"e"] 
h = reordered.zip(alpha).to_h 
    # => {"f"=>"a", "g"=>"b",..., "z"=>"u", "a"=>"v",..., e"=>"z"} 

text_array.sort_by { |w| w.gsub(/./,h) } 
    #=> ["frank", "george", "harry", "isaac", "jordan", 
    # "alice", "bob", "carol", "dave", "eve"] 

Вариант из этого:

a_to_z = alpha.join 
    #=> "abcdefghijklmnopqrstuvwxyz" 
f_to_e = reordered.join 
    #=> "fghijklmnopqrstuvwxyzabcde" 

text_array.sort_by { |w| w.tr(f_to_e, a_to_z) } 
    #=> ["frank", "george", "harry", "isaac", "jordan", 
    # "alice", "bob", "carol", "dave", "eve"] 
+1

Мне нравится замена шифрования первого решения. –

+0

@MarkThomas, я решил, что это было лучше, чем # 2, поэтому удалил второй. –

+1

['tr'] (http://ruby-doc.org/core-2.2.1/String.html#method-i-tr) принимает диапазоны символов, то есть' text_array.sort_by {| w | w.tr ('f-za-e', 'a-z')} ' – Stefan

0

Если у меня есть вопрос правильно, похоже, вы хотите создать отсортированный список с предвзятым предварительным .

ie. допустим, вы хотите определить конкретный шаблон текста, который может полностью изменить последовательность сортировки для элемента массива.

Вот мое предложение, вы можете получить лучший код из этого, но мой уставший мозг получил его сейчас -

an_array = ["bob", "alice", "dave", "carol", "frank", "eve", "jordan", "isaac", "harry", "george"] 

# Define your patterns with scores so that the sorting result can vary accordingly 
# It's full fledged Regex so you can put any kind of regex you want. 
patterns = { 
    /^f/ => 100, 
    /^e/ => -100, 
    /^g/ => 60, 
    /^j/ => 40 
} 

# Sort the array with our preferred sequence 
sorted_array = an_array.sort do |left, right| 
    # Find score for the left string 
    left_score = patterns.find{ |p, s| left.match(p) } 
    left_score = left_score ? left_score.last : 0 

    # Find the score for the right string 
    right_score = patterns.find{ |p, s| right.match(p) } 
    right_score = right_score ? right_score.last : 0 

    # Create the comparision score to prepare the right order 
    # 1 means replace with right and -1 means replace with left 
    # and 0 means remain unchanged 
    score = if right_score > left_score 
    1 
    elsif left_score > right_score 
    -1 
    else 
    0 
    end 

    # For debugging purpose, I added few verbose data 
    puts "L#{left_score}, R:#{right_score}: #{left}, #{right} => #{score}" 

    score 
end 

# Original array 
puts an_array.join(', ') 

# Biased array 
puts sorted_array.join(', ')