Вот что я сделал:
Я расколол ваш файл данных в более длинный формат, а затем сгруппировал его по столбцу имен. В каждой группе я бросаю 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
Я могу получить то, что я хочу путем вызова inject
a = [{:a => 1},{:a => 2}, {:a => 1}]
a.inject([]) { |result,h| result << h unless result.include?(h); result }
, Это возвратится:
[{:a=>1}, {:a=>2}]
Принятие Ваших хешей всегда является единственными парами "ключ-значение", это будет работать:
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]]
и затем вторая карта откладывает их вместе как хеши снова.
Ответ, который Вы даете, подобен тому, обсудил здесь . Это переопределяет hash
и eql?
методы на хешах, которые должны появиться в массиве, который тогда делает uniq
, ведут себя правильно.
найденный на Google http://mikeburnscoder.wordpress.com/2008/01/18/uniquify-an-array-of-hashes-in-ruby/
У меня была похожая ситуация, но у хэшей были ключи. Я использовал метод сортировки.
Что я имею в виду:
у вас есть массив:
[{: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)