콜린의에서 약간 수정 된 버전입니다.
class Hash
def diff(other)
(self.keys + other.keys).uniq.inject({}) do |memo, key|
unless self[key] == other[key]
if self[key].kind_of?(Hash) && other[key].kind_of?(Hash)
memo[key] = self[key].diff(other[key])
else
memo[key] = [self[key], other[key]]
end
end
memo
end
end
end
이보다 효율적으로 왼쪽과 오른쪽
{a: {c: 1, b: 2}, b: 2}.diff({a: {c: 2, b: 2}})
반환
{:a=>{:c=>[1, 2]}, :b=>[2, nil]}
대신
{:a=>[{:c=>1, :b=>2}, {:c=>2, :b=>2}], :b=>[2, nil]}
에 대한 해시로 재귀 좋은 생각 콜린
여기
그래서 당신은
{a: {c: 2, b: 2}, b: nil}
얻을 얻을
{a: {c: 1, b: 2}, b: 2}.apply_diff({:a=>{:c=>[1, 2]}, :b=>[2, nil]})
를 실행할 권리 등의 왼쪽 모양을 만들기 위해 원래의 해시
def apply_diff!(changes, direction = :right)
path = [[self, changes]]
pos, local_changes = path.pop
while local_changes
local_changes.each_pair {|key, change|
if change.kind_of?(Array)
pos[key] = (direction == :right) ? change[1] : change[0]
else
path.push([pos[key], change])
end
}
pos, local_changes = path.pop
end
self
end
def apply_diff(changes, direction = :right)
cloned = self.clone
path = [[cloned, changes]]
pos, local_changes = path.pop
while local_changes
local_changes.each_pair {|key, change|
if change.kind_of?(Array)
pos[key] = (direction == :right) ? change[1] : change[0]
else
pos[key] = pos[key].clone
path.push([pos[key], change])
end
}
pos, local_changes = path.pop
end
cloned
end
에은 diff를 적용하는 방법입니다 정확히 우리는 조금 더 멀리 가야하고 아무 것도없고 아무 것도없는 키의 차이를 기록해야합니다.
그리고 그냥 추가 및 제거를 제공하여 긴 배열을 단축하는 것이 좋을 것입니다.
내 목적을 위해 어떤 필드가 변경되었는지 알 필요가 있기 때문에 특별히 신경 쓰지 않습니다. AR을 사용했다면 문제가되지 않지만 데이터 레이어를 통해 모든 것이 CouchDB로 추상화되므로 휠체어를 재발 명해야한다는 것을 알게되었습니다. 제안에 감사드립니다. – Chelsea
물론 "brute force"에 해당하는 댓글이 있지만 유용하고 너무 끔찍하지는 않습니다. –
이 방법은 개선 된 버전 확인을 위해 키 부재가 값이 'nil'이 아니라는 것을 '기타'해시에 추가 키가 있음을 알 수 없으며 http://stackoverflow.com/a/19184270/54247 – dolzenko