2010-04-20 5 views
3

При условии, что следующий рубин хэш:Сортировка вложенного хэша в рубине

{ 
    cat: { 
     1: 2, 
     2: 10, 
     3: 11, 
     4: 1 
    }, 
    wings: { 
     1: 3, 
     2: 5, 
     3: 7, 
     4: 7 
    }, 
    grimace: { 
     1: 4, 
     2: 5, 
     3: 5, 
     4: 1 
    }, 
    stubborn: { 
     1: 5, 
     2: 3, 
     3: 7, 
     4: 5 
    } 
} 

Как можно отсортировать хэш по сумме «лист» за исключением «4», например, значение для сравнения для «кошек» будет (2 + 10 + 11) = 23, значение для «крыльев» было бы (3 + 5 + 7) = 15, поэтому, если бы я сравнивал только эти два, они были бы в правильном порядке, высшая сумма сверху.

Можно с уверенностью предположить, что он ВСЕГДА будет {1: значение, 2: значение, 3: значение, 4: значение}, поскольку это ключи для констант, которые я определил.

Также можно предположить, что я только когда-либо хочу, чтобы исключить ключ «4», и всегда используйте клавиши «1», «2» и «3»

На основании предположения I Джордана получил эту работу:

tag_hash = tag_hash.sort_by do |h| 
    h[1].inject(0) do |sum, n| 
     n[0] == 4 ? sum : sum + (n[1] || 0) 
    end 
    end 

результаты кажутся немного прочь, но это, кажется, мой код, когда я подтверждаю, что я принимаю ответ, спасибо Джордана!

Я обновил свое решение, чтобы использовать идею Уэйна Конрада, см. Мой комментарий к его ответу - возможно ли, что он не несет все, когда он сортируется, я связан с изображением в своем комментарии, который показывает результат фактического сортировать в виде графика .. кажется странным для меня ..

ответ

8
tag_hash = tag_hash.sort_by do |_, leaf| 
    leaf.reject do |key, _| 
    key == 4 
    end.collect(&:last).inject(:+) 
end 
+0

+1, хорошее решение. Я не знаю, почему так много людей отказываются использовать деструктурирующую привязку, например, решение Иордании является ужасно уродливым из-за того, что оно не используется. Одно предложение: замените внешний параметр 'key' на' _', чтобы он понял, что вы его нигде не используете. –

+0

Это то же самое (но более эстетично), но я нарисовал результаты из своего рода, и это то, что вышло с помощью http://imgur.com/NFxfM, кажется странным .. он сортируется .. но это почти похоже на то, что он не отсортирован достаточно. – Rabbott

+0

Jörg: Я согласен с тем, что мое решение менее симпатично, чем Уэйн, но одно инъекция показалось мне более эффективным, чем цепочка reject-> collect-> inject. Я предпочитаю перебирать структуру данных меньше, когда это возможно. –

2
my_hash.sort_by do |_, h| 
    h.inject(0) do |sum, n| 
    # only add to the sum if the key isn't '4' 
    n[0] == 4 ? sum : (sum + n[1]) 
    end 
end 

Это может, конечно, быть сокращен до безобразия нечитаемым однострочника:

my_hash.sort_by {|k,h| h.inject(0) {|sum,n| n[0] == 4 ? sum : (sum + n[1]) } } 
+0

Я получаю «Массив не может быть принужден к Fixnum» ... – Rabbott

+0

Да это не достаточно глубоко, похоже, она должна идти на один уровень глубже для добавления. – Rabbott

+0

Извините, Рабботт, вы правы. Я обновил свой код. –

0

Это

puts a.sort_by { |k, v| -v.values[0..-1].inject(&:+) } 

производит следующий результат: это было то, что вы хотели?

cat 
{1=>2, 2=>10, 3=>11, 4=>1} 
wings 
{1=>3, 2=>5, 3=>7, 4=>7} 
stubborn 
{1=>5, 2=>3, 3=>7, 4=>5} 
grimace 
{1=>4, 2=>5, 3=>5, 4=>1} 
0

Это похоже на работу:

x.sort_by{ |_,h| h.values.take(3).inject(:+) } 

Это предполагает, что subhashes сортируются (первые три записи являются записи, которые вы хотите, чтобы подвести итоги).

При использовании ActiveSupport вы можете сделать это:

x.sort_by{ |_,h| h.values.take(3).sum } 

или

x.sort_by{ |_,h| h.slice(1,2,3).values.sum } 

Hash # ломтика возвращает хэш, содержащий только ключи, переданные порезать. Array # take возвращает массив, содержащий первые n записей исходного массива.

(Ruby 1.9.1 требуется я думаю)

 Смежные вопросы

  • Нет связанных вопросов^_^