2014-01-22 3 views
1

Я создаю список хэшей в массиве и хотел бы сохранить счет, если они одинаковы.Подсчет объектов в массиве Ruby

Вот что пример хэш выглядит следующим образом:

data = { 
    s: y.id, 
    t: z.id, 
    count: 0 
} 

Я итерацию через кучу этих хэшей и толкая их на список. Мне бы хотелось, чтобы, когда значения для s и t уже существуют в хеше в списке, count будет увеличиваться.

Позвольте пояснить. Пусть это мой @list

@list = [ 
    { 
     s: 1, 
     t: 2, 
     count: 5 
    }, 
    { 
     s: 1, 
     t: 3, 
     count: 5 
    } 
] 

Теперь предположим, я хочу выдвинуть следующий хэш списка:

data = { 
    s: 1, 
    t: 2, 
    count: 0 
} 

Результат @list должен выглядеть следующим образом потому, что хэш с s==1 и t==2 уже существует в списке:

@list = [ 
    { 
     s: 1, 
     t: 2, 
     count: 6 
    }, 
    { 
     s: 1, 
     t: 3, 
     count: 5 
    } 

]

Вот где я сейчас.

@final = [] 

while widgets.count > 1 
    widget = widgets.shift 
    widgets.each do |w| 
     data = { 
      s: widget.id, 
      t: w.id, 
      count: 0 
     } 
     @final << data 
    end 
end 

Это просто добавляет все перестановки в список, но я хочу, чтобы предотвратить Dups когда s и t идентичны и просто увеличивает count.

Надеюсь, я поняла.

Любые предложения были бы весьма полезными.

+1

Have A посмотрите [этот вопрос] (http://stackoverflow.com/questions/4351793/is-there-a-bag-implementation-in-ruby) для общей реализации подсчитанного множества. – Sebastian

+0

Некоторые тесты позволили бы избежать путаницы :) – Rimian

+0

Я добавил, что я понял, что вы объяснили это - тесты были бы полезны, это правда :-) –

ответ

1

Я бы сделать это так (при условии, я понимаю вопрос правильно):

def add_hash(data) 
    h, i = @list.each_with_index.find {|h,i| data[:s]==h[:s] && data[:t]==h[:t]} 
    if h 
    @list[i][:count] += 1 
    else 
    data[:count] = 1 
    @list << data 
    end 
end 

add_hash({ s: 1, t: 3, count: 0 }) 
@list # @list => [{:s=>1, :t=>2, :count=>5}, {:s=>1, :t=>3, :count=>6}] 

add_hash({ s: 2, t: 3, count: 0 }) 
@list # @list # => [{:s=>1, :t=>2, :count=>5}, {:s=>1, :t=>3, :count=>5}, 
        {:s=>2, :t=>3, :count=>1}] 

Если вы можете изменить @list, рассмотреть возможность сделать это хэш:

@hash = { { s: 1, t: 2 } => 5, { s: 1, t: 3 } => 5 } 
0

Не уверен ли я intepreting ваш вопрос правильно, но если вы хотите, чтобы атрибут count в каждом data хэш будет увеличиваться при data.s == data.t, это должно сделать трюк:

@final = [] 

while widgets.count > 1 
    widget = widgets.shift 
    widgets.each do |w| 
     data = { 
      s: widget.id, 
      t: w.id, 
      count: 0 
     } 
     if data.s == data.t 
      data.count += 1 
     end 
     @final << data 
    end 
end 
+0

Это близко. Я имел в виду, когда data.s и data.t уже существуют в массиве @final для существующего объекта. В этом случае я хотел бы просто увеличить счет. –

+0

Я только что обновил свой пост, чтобы быть более понятным. Извините за путаницу. –

1

Если я получаю свой вопрос прямо вы можете использовать метод find в списке, передающем блок, в котором вы указываете условия, которые вы хотите сопоставить (эти значения s и t уже присутствуют в списке @final).
Это пример использования списков и хешей.

widgets = [{s:1, t:2, count:0}, {s: 1, t:2, count:0}, {s: 1, t:2, count:0},  
{s:1, t:3, count:0}, {s:1, t:3, count:0}]  
@final = []  

widgets.each do |widget|  
    res = @final.find {|obj| obj[:s] == widget[:s] && obj[:t] == widget[:t] }  
    if res.nil?  
    widget[:count] = 1  
    @final << widget  
    else  
    res[:count] += 1  
    end  
end  

puts @final.inspect 

И ответ от этого кода

[{:s=>1, :t=>2, :count=>3}, {:s=>1, :t=>3, :count=>2}] 

, как и ожидалось

0
def reduce_matches(collection) 
    result.reduce([]) do |arr, element| 
    matching(arr, element) ? matching[:count] += 1 : arr << element 
    arr 
    end 
end 

def matching(coll, candidate) 
    coll.detect do |element| 
    element[:s] == candidate[:s] && element[:t] == candidate[:t] 
    end 
end 

Теперь вы можете ввести:

reduce_matches(widgets) 

, который дает вам то, что вам нужно.Например, если

widgets = [ 
    { 
    s: 1, 
    t: 2, 
    count: 0 
    }, 
    { 
    s: 2, 
    t: 3, 
    count: 0 
    }, 
    { 
    s: 1, 
    t: 2, 
    count: 0 
    }, 
] 

затем

reduce_matches(widgets) = [ 
    { 
    s: 1, 
    t: 2, 
    count: 1 
    }, 
    { 
    s: 2, 
    t: 3, 
    count: 0 
    } 
] 

Хотите добавить новый элемент виджетов?

widgets << new_element 
reduce_matches(widgets) 
Смежные вопросы