2016-10-04 3 views
-2

그래서 2D 배열이 있다고 가정 해보십시오. 아마 뭔가 같은 :중복을 기반으로 2D 배열 요소를 합치는 가장 간단한 방법은 무엇입니까?

data = [['oct 1', 4], ['oct 2', 5], ['oct 3', 9], ['oct 1', 2]] 

그리고 나는이 밖으로 새 배열을 얻으려면, 그 중복 값을 제거하지만 해당 값을 요약한다 (예를 들면 년 10 월 1.). ,

data = (['oct 1', 6], ['oct 2', 5], ['oct 3', 9]) 
나는이 작업을 수행 할 수있는 몇 가지 방법을 생각할 수

하지만 그들은 꽤 inefficent 것 일반적으로 항상 몇 줄에 아무것도 할 수있는 몇 가지 미친 루비 코드가있다 :

그래서 나는 끝낼 것 어떤 제안? inject 방법 다음

+0

우리는이 문제를 해결하려는 시도를보고 싶습니다. 그 노력의 증거가 없다면, 우리는 당신이해야 할 일을 우리가하기를 원하는 것처럼 보입니다. "[ask]", "[mcve]"및 "[Stack Overflow 사용자에 대한 연구 노력의 정도] (http://meta.stackoverflow.com/a/261593/128421)"를 읽어보십시오. –

답변

2

는 내 취향이 처음 인 그 일을 몇 가지 방법입니다.

def combine(data) 
    data.each_with_object(Hash.new(0)) { |(date, val), h| h[date] += val }.to_a 
end 

Hash::new, 특히 기본 값의 설명을 참조하십시오

코드 계산 해시

를 사용합니다.

data = [['oct 1', 4], ['oct 2', 5], ['oct 3', 9], ['oct 1', 2]] 
combine data 
    #=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]] 

설명

enum = data.each_with_object(Hash.new(0)) 
    #=> #<Enumerator: [["oct 1", 4], ["oct 2", 5], ["oct 3", 9], 
    #     ["oct 1", 2]]:each_with_object({})> 

우리는 배열로 변환하여 계수기에 의해 생성 된 값을 알 수있다.

enum.to_a 
    #=> [[["oct 1", 4], {}], [["oct 2", 5], {}], [["oct 3", 9], {}], 
    # [["oct 1", 2], {}]] 

enum의 첫번째 값이 블록에 전달하고, 블록의 변수의 값과 동음평행 할당을 사용하여 계산된다. 지금

(date, val), h = enum.next #=> [["oct 1", 4], {}] date #=> "oct 1" val #=> 4 h[date] += val #=> h[date] = h[date] + val #=> h["oct 1"] = h["oct 1"] + 4 #=> h["oct 1"] = 0 + 4 (no key "oct 1" so default value of `0` used) #=> h["oct 1"] = 4 

, enum

h #=> {"oct 1"=>4} 

나머지 세 값이 블록에 전달하고, 블록 계산이 수행된다.

사용 Enumerable#group_by

h[date] += val 
    #=> h[date] = h[date] + val 
    #=> h["oct 1"] = h["oct 1"] + 2 
    #=> h["oct 1"] = 4 + 2 

마지막으로,

h.to_a 
    #=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]] 

: 해시 h 이미 키 "oct 1" 있었기 때문에 마지막 계산에서

(date, val), h = enum.next #=> [["oct 2", 5], {"oct 1"=>4}] h[date] += val #=> 5 (the default value of `0` is again used) h #=> {"oct 1"=>4, "oct 2"=>5} (date, val), h = enum.next #=> [["oct 3", 9], {"oct 1"=>4, "oct 2"=>5}] h[date] += val #=> 9 (the default value of `0` is again used) h #=> {"oct 1"=>4, "oct 2"=>5, "oct 3"=>9} (date, val), h = enum.next #=> [["oct 1", 2], {"oct 1"=>4, "oct 2"=>5, "oct 3"=>9}] h[date] += val #=> 6 h #=> {"oct 1"=>6, "oct 2"=>5, "oct 3"=>9} 

는 기본값이 사용되지 않았습니다

코드

def combine(data) 
    data.group_by(&:first).map { |date, vals| [date, vals.map(&:last).reduce(:+)] } 
end 

combine data 
    #=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]] 

설명

단계 :

h = data.group_by(&:first) 
    #=> {"oct 1"=>[["oct 1", 4], ["oct 1", 2]], 
    # "oct 2"=>[["oct 2", 5]], "oct 3"=>[["oct 3", 9]]} 

h E의 제 키 - 값 쌍 블록으로 전달된다 :

date, vals = h.first 
    #=> ["oct 1", [["oct 1", 4], ["oct 1", 2]]] 
date 
    #=> "oct 1" 
vals 
    #=> [["oct 1", 4], ["oct 1", 2]] 

과 블록 연산이 수행된다.

a = vals.map(&:last) 
    #=> [4, 2] 
t = a.reduce(:+) 
    #=> 6 

는 그래서 h의 첫번째 키 - 값 쌍

[date, t] 
    #=> ["oct 1", 6] 

나머지 계산은 유사한 매핑된다.

+0

감사합니다. 훌륭한 답변입니다. 내 코드 형식에 관해서는, 나는 사이트에 처음 온 것이므로 의사 구현은 괜찮을 것이라고 생각했다. – LukeCage

+0

예를 들어 4D 배열로 일반화하는 방법에 대한 팁은 무엇입니까? – LukeCage

+0

배열이 어떻게 생겼는지에 따라 달라집니다. 예를 들어, 같은 키가 다른 "레벨"에 존재합니까? 별도의 질문을 게시하는 것이 가장 좋습니다 (예를 들어). –

1

시도 : 여기

data = [["oct 1", 4], ["oct 2", 5], ["oct 3", 9], ["oct 1", 2]] 
data.inject({}) { |sum, (n, t)| sum[n] ||= 0; sum[n] += t; sum }.to_a 
=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]] 
관련 문제