Remover registros que são duplicados e somar os valores

512 views
Skip to first unread message

Esmerino

unread,
Aug 1, 2012, 10:13:05 AM8/1/12
to rub...@googlegroups.com
Eu tenho um hash assim:

list=[
 
{:cod => "0001", :name => "name1", :val => 10},
 
{:cod => "0001", :name => "name1", :val => 10},
 
{:cod => "0002", :name => "name2", :val => 10},
 
{:cod => "0002", :name => "name2", :val => 10},
 
{:cod => "0004", :name => "name4", :val => 10},
 
{:cod => "0004", :name => "name4", :val => 10},
 
{:cod => "0004", :name => "name4", :val => 10},
 
{:cod => "0005", :name => "name5", :val => 10},
 
{:cod => "0005", :name => "name5", :val => 10}
 
]
O que eu gostaria de aprender é como remover os registros são duplicados e somar os valores :val.
list=[
 
{:cod => "0001", :name => "name1", :val => 20},
 
{:cod => "0002", :name => "name2", :val => 20},
....
]
Grato.


Anderson Dias

unread,
Aug 1, 2012, 10:16:11 AM8/1/12
to rub...@googlegroups.com
Para achar os valores unicos use: list.uniq
--
Anderson Dias



2012/8/1 Esmerino <haka...@gmail.com>

--
Você recebeu esta mensagem porque está inscrito no Grupo "ruby-sp" em
Grupos do Google.
Para postar neste grupo, envie um e-mail para rub...@googlegroups.com
Para cancelar a sua inscrição neste grupo, envie um e-mail para
ruby-sp+u...@googlegroups.com
Para ver mais opções, visite este grupo em
http://groups.google.com.br/group/ruby-sp?hl=pt-BR
Página oficial do GURU-SP: http://www.guru-sp.org

Esmerino Jr

unread,
Aug 1, 2012, 10:39:55 AM8/1/12
to rub...@googlegroups.com
Obrigado pela resposta Anderson, mas meu problema é somar os valores do val.

list.uniq ou list.sort_by(&:code).inject([]){ |m,e| m.last.nil? ? [e] : m.last[:code] == e[:code] ? m : m << e }  remove os valores duplicado e retorna o array,mas não retorna o array com o campo val somados para o :code duplicado. Obrigado novamente pela resposta.

2012/8/1 Anderson Dias <anderso...@gmail.com>

Anderson Cardoso

unread,
Aug 1, 2012, 12:02:04 PM8/1/12
to rub...@googlegroups.com
keep it simple. Pq escrever um código criptico se vc pode simplesmemte iterar sobre a lista?
abs
Anderson Pierre Cardoso
Computer Engineer - University of São Paulo

http://www.apierrecardoso.com

twitter: @apierre_cardoso


Douglas Rossignolli

unread,
Aug 1, 2012, 11:02:33 AM8/1/12
to rub...@googlegroups.com
Bem, sou iniciante em rails também

e acho que a sua solução e ate simples:

seria -/+ isso o seu algoritimo
def soma_valores
nova_list = {}
list.each do |e|
# se nao houver este codigo add 
if procura_chave_na_lista(code)
# adiciona 
else 
#se nao soma
end 
end 
end

Bruno Andrade

unread,
Aug 1, 2012, 11:41:47 AM8/1/12
to rub...@googlegroups.com
Fala Esmerino!

Tenta assim

list.uniq.map{|hash| hash[:val]}.reduce(&:+)


abraço 

Bruno Andrade

unread,
Aug 1, 2012, 12:17:56 PM8/1/12
to rub...@googlegroups.com
Anderson,

Eu apenas coloquei a solução as pressas, contudo interar na lista é possivel mas não necessário

registros_nao_duplicados =   list.uniq
valores = registros_nao_duplicados.map{|hash| hash[:val]}
valores.reduce(&:+)


melhor assim?

abraço

Esmerino Jr

unread,
Aug 1, 2012, 1:22:20 PM8/1/12
to rub...@googlegroups.com
Obrigado pela reposta Anderson,mas ele só deve dar um reduce(&:+) nos valores que tenha os cod: iguais:

 [{:cod => "0001", :name => "name1", :val => 10},

 
{:cod => "0001", :name => "name1", :val => 10},
 
{:cod => "0002", :name => "name2", :val => 10},

 
{:cod => "0002", :name => "name2", :val => 10}]
reduce(&:+) deve ser somente para o mesmo :cod. e não para todos, que ficaria assim:
[{:cod => "0001", :name => "name1", :val => 20},
{:cod => "0002", :name => "name2", :val => 20}]

Esse é o meu problema.

2012/8/1 Bruno Andrade <brun...@gmail.com>

Renato Riccieri Santos Zannon

unread,
Aug 1, 2012, 11:00:38 PM8/1/12
to rub...@googlegroups.com
Não é o código mais bonito do planeta, mas acho que resolve seu
problema:

grouped_hashes = list.group_by { |hash| hash.values_at(:cod, :name) }

grouped_hashes.map do |(cod, name), hashes|
sum_from_group = hashes.map { |hash| hash[:val] }.inject(:+)

{ cod: cod, name: name, val: sum_from_group }
end

Só tome cuidado com Primitive Obsession
<http://solnic.eu/2012/06/25/get-rid-of-that-code-smell-primitive-obsession.html>,
talvez você tenha alguma classe aí querendo aparecer.

Abraço!

Em 01-08-2012 14:22, Esmerino Jr escreveu:
> Obrigado pela reposta Anderson,mas ele só deve dar um reduce(&:+) nos
> valores que tenha os cod: iguais:
>
> [{:cod => "0001", :name => "name1", :val => 10},
> {:cod => "0001", :name => "name1", :val => 10},
> {:cod => "0002", :name => "name2", :val => 10},
> {:cod => "0002", :name => "name2", :val => 10}]
>
> reduce(&:+) deve ser somente para o mesmo :cod. e não para todos, que
> ficaria assim:
>
> [{:cod => "0001", :name => "name1", :val => 20},
> {:cod => "0002", :name => "name2", :val => 20}]
>
> Esse é o meu problema.

--
@renato_bill
Renato Zannon

signature.asc

Esmerino Jr

unread,
Aug 1, 2012, 11:25:37 PM8/1/12
to rub...@googlegroups.com
Renato, obrigado pela resposta. Estava discutindo com um amigo e chegamos a uma solução:

list=[

 
{:cod => "0001", :name => "name1", :val => 10},
 
{:cod => "0001", :name => "name1", :val => 10},
 
{:cod => "0002", :name => "name2", :val => 10},

 
{:cod => "0002", :name => "name2", :val => 10},

 
{:cod => "0004", :name => "name4", :val => 10},
 
{:cod => "0004", :name => "name4", :val => 10},
 
{:cod => "0004", :name => "name4", :val => 10},

 
{:cod => "0005", :name => "name5", :val => 10},

 
{:cod => "0005", :name => "name5", :val => 10}

 
]
list.inject(Hash.new(0)) { |hash, el| hash[el[:cod]] += el[:val] ; hash }
Sim, Renato vou providenciar uma class para resolver esse comportamento e obrigado pelo link. 
Abraço.

2012/8/2 Renato Riccieri Santos Zannon <renato....@gmail.com>

André Tagliati

unread,
Aug 1, 2012, 1:27:21 PM8/1/12
to rub...@googlegroups.com
Dai nesse caso o ideal não seria jogar pra hash enquanto itera?
Verifica se o name já existe no novo hash. Se não adiciona. Se sim soma val.

2012/8/1 Esmerino Jr <jose.e...@gmail.com>



--
Atenciosamente,
André Tagliati
http://www.tagliati.com.br

Natanael A.S.

unread,
Aug 1, 2012, 7:12:14 PM8/1/12
to rub...@googlegroups.com
Esmerino,

Se os registros forem sempre idênticos, acho que isso resolve:

list.uniq.map { |h| list.select { |x| x[:cod] == h[:cod] }.map { |h|
h[:val] }.reduce(&:+); h }

Se os valores vão variar, então é melhor agrupar por código:

list.group_by { |x| x[:cod] }.values.map { |values|
values.reduce { |b, a| b.merge(a) { |i, v, nv| i == :val ? v + nv : nv }}
}

Ta bem feio, mas acho que é por aí.

Abraço

--
Natanael

Rogerio Medeiros

unread,
Aug 1, 2012, 2:43:02 PM8/1/12
to rub...@googlegroups.com
Pupilo lol


totals = Hash.new(0)
list.each do |entry|
  totals[entry[:cod]] += entry[:val]
end
--
att,

Rogerio

A complicação se descomplica na mesma proporção que fazemos os nós se desatarem ao tecer o conhecimento do saber.

Esmerino Jr

unread,
Aug 2, 2012, 11:37:04 AM8/2/12
to rub...@googlegroups.com
Americodls,

Sim, é uma outra solução para esse problema. Obrigado pela resposta.

Abraço.

2012/8/1 americodls <ameri...@gmail.com>
Hey bro, veja se é isso aki:

list.group_by{|e|e[:cod]}.map{|k,v|[k,v.map{|e|e[:val]}.reduce(&:+)]}

Curti o o desafio! Espero que ajude. Abraço!

Hugo A. G. V. Rosa

unread,
Aug 2, 2012, 12:06:13 PM8/2/12
to rub...@googlegroups.com
Eu só não trocaria:

.map{|hash| hash[:val]}.reduce(&:+)

por

.reduce(0) { |sum, hash| sum + hash[:val] }

--
Hugo A. G. V. Rosa
Inĝenieristo, matematikulo kaj scivolulo
http://friendfeed.com/hugoxrosa

Régis Mesquita

unread,
Aug 2, 2012, 12:22:29 PM8/2/12
to rub...@googlegroups.com
Você quis dizer trocaria né? fica bem mais legivel com o reduce direto.

sua_array.uniq.reduce(0){|sum , value| sum + value}

Lembrando que se tiver no rails ainda pode usar o sum.

sua_array.uniq.sum{ |item| item[:val] }

e que se ao invés de hash forem objetos com um metodo value ficará ainda mais legivel:

sua_array.uniq.sum(&:value)

Hugo A. G. V. Rosa

unread,
Aug 6, 2012, 1:00:10 PM8/6/12
to rub...@googlegroups.com
Em 2 de agosto de 2012 13:22, Régis Mesquita
<re...@regismesquita.com.br> escreveu:
> Você quis dizer trocaria né? fica bem mais legivel com o reduce direto.
>

Exato, trocaria... foi mal.

--
"Aqui deveria ter uma tagline."
Reply all
Reply to author
Forward
0 new messages