Как я получаю уникальные элементы от массива хешей в Ruby?

Вот что я сделал:

Я расколол ваш файл данных в более длинный формат, а затем сгруппировал его по столбцу имен. В каждой группе я бросаю NaNs, но затем пересказываю полный набор h1 мысли h4, тем самым воссоздавая ваши NaN справа.

from io import StringIO
import pandas

def defragment(x):
    values = x.dropna().values
    return pandas.Series(values, index=df.columns[:len(values)])

datastring = StringIO("""\
Name    h1    h2    h3    h4
A       1     nan   2     3
B       nan   nan   1     3
C       1     3     2     nan""")

df = pandas.read_table(datastring, sep='\s+').set_index('Name')
long_index = pandas.MultiIndex.from_product([df.index, df.columns])

print(
    df.stack()
      .groupby(level='Name')
      .apply(defragment)
      .reindex(long_index)  
      .unstack()  
)

И вот я получаю:

   h1  h2  h3  h4
A   1   2   3 NaN
B   1   3 NaN NaN
C   1   3   2 NaN
24
задан Aaron Hinni 9 October 2008 в 11:18
поделиться

5 ответов

Я могу получить то, что я хочу путем вызова inject

a = [{:a => 1},{:a => 2}, {:a => 1}]
a.inject([]) { |result,h| result << h unless result.include?(h); result }

, Это возвратится:

[{:a=>1}, {:a=>2}]
27
ответ дан Aaron Hinni 28 November 2019 в 23:06
поделиться

Принятие Ваших хешей всегда является единственными парами "ключ-значение", это будет работать:

a.map {|h| h.to_a[0]}.uniq.map {|k,v| {k => v}}

Хеш to_a создает массив массивов значения ключа, таким образом, первая карта получает Вас:

[[:a, 1], [:a, 2], [:a, 1]]

uniq на Массивах делает то, что Вы хотите, давая Вам:

[[:a, 1], [:a, 2]]

и затем вторая карта откладывает их вместе как хеши снова.

3
ответ дан glenn mcdonald 28 November 2019 в 23:06
поделиться

Ответ, который Вы даете, подобен тому, обсудил здесь . Это переопределяет hash и eql? методы на хешах, которые должны появиться в массиве, который тогда делает uniq, ведут себя правильно.

0
ответ дан Mark Reid 28 November 2019 в 23:06
поделиться
0
ответ дан edthix 28 November 2019 в 23:06
поделиться

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

Что я имею в виду:

у вас есть массив:

[{:x=>1},{:x=>2},{:x=>3},{:x=>2},{:x=>1}]

вы сортируете его ( #sort_by {| t | t [: x]} ) и получаете это:

[{:x=>1}, {:x=>1}, {:x=>2}, {:x=>2}, {:x=>3}]

Теперь немного измененная версия ответа Аарона Хинни:

your_array.inject([]) do |result,item| 
  result << item if !result.last||result.last[:x]!=item[:x]
  result
end

Я также попробовал:

test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]}

, но это очень медленно. Вот мой тест:

test=[]
1000.times {test<<{:x=>rand}}

Benchmark.bmbm do |bm|
  bm.report("sorting: ") do
    test.sort_by {|t| t[:x]}.inject([]) {|r,h| r<<h if !r.last||r.last[:x]!=h[:x]; r}
  end
  bm.report("inject: ") {test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]} }
end

Результаты:

Rehearsal ---------------------------------------------
sorting:    0.010000   0.000000   0.010000 (  0.005633)
inject:     0.470000   0.140000   0.610000 (  0.621973)
------------------------------------ total: 0.620000sec

                user     system      total        real
sorting:    0.010000   0.000000   0.010000 (  0.003839)
inject:     0.480000   0.130000   0.610000 (  0.612438)
5
ответ дан 28 November 2019 в 23:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: