키로 해시 정렬, 루비에서 해시 반환


257

이것이 해시를 정렬하고 배열 대신 해시 객체를 반환하는 가장 좋은 방법입니까?

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
# => {"a"=>1, "c"=>3, "b"=>2, "d"=>4}

Hash[h.sort]
# => {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

9
해시를 사용 each하거나 each_pair반복 하지 않는 한 해시를 정렬하는 데 많은 이점이 있는지 확실하지 않습니다 . 그럼에도 불구하고 필자는 여전히 키를 잡고 정렬 한 다음 필요에 따라 값을 가져 와서 반복합니다. 이렇게하면 코드가 이전 Rubies에서 올바르게 작동합니다.
Tin Man

루비 1.9에서도 의미가 있습니다. DB에서 오는 날짜 (키로)별로 약속 모음이 있고 루비를 통해 수동으로 정렬했습니다. 예 : { "2012-09-22": [...], "2012-09-30": [...], "2012-10-12": [...]}
Adit Saxena

네, Hash [h.sort] 프로세스가 키를 정렬하는 것보다 더 효과적이며 정렬 된 키를 통해 해시에 다시 액세스합니다.
Douglas


3
몇 년 동안 솔루션에 대해 생각해 보았습니다. 답변을받을 준비가 되셨습니까? ;-)
Mark Thomas

답변:


219

Ruby 2.1에서는 간단합니다 :

h.sort.to_h

@zachaysan하지만 작동합니다 : h.sort{|a,z|a<=>z}.to_h(2.1.10, 2.3.3 테스트)
whitehat101

@ whitehat101 당신이 맞아요. 버그가있었습니다 (키 a가 아닌 배열입니다). 내 댓글을 삭제했습니다.
zachaysan

다른 사람이 해시 배열을 정렬하는 방법을 찾고있는 경우 트릭을 수행합니다 (여기서 h는 배열 임) h.map(&:sort).map(&:to_h).
JM Janzen

82

참고 : Ruby> = 1.9.2에는 주문 보존 해시가 있습니다. 주문 키가 삽입되는 순서가 입력됩니다. 아래는 이전 버전 또는 이전 버전과 호환되는 코드에 적용됩니다.

정렬 된 해시 개념이 없습니다. 그래서, 당신이하고있는 일은 옳지 않습니다.

표시를 위해 정렬하려면 문자열을 반환하십시오.

"{" + h.sort.map{|k,v| "#{k.inspect}=>#{v.inspect}"}.join(", ") + "}"

또는 키를 순서대로 원할 경우 :

h.keys.sort

또는 순서대로 요소에 액세스하려는 경우 :

h.sort.map do |key,value|
  # keys will arrive in order to this block, with their associated value.
end

그러나 요약하면 정렬 된 해시에 대해 이야기하는 것은 의미가 없습니다. 로부터 문서 , "당신도 키 또는 값으로 해시를 통과하는 순서는 임의 보일 수 있으며, 일반적으로 삽입 순서가 맞지 않습니다." 따라서 해시에 특정 순서로 키를 삽입해도 도움이되지 않습니다.


맞습니다. RBtree gem을 사용하여 루비에서 순서가 설정된 기능을 얻는 것이 좋습니다.
Aaron Scruggs

26
1.9.2부터는 해시 삽입 순서가 유지됩니다. 참조 redmine.ruby-lang.org/issues/show/994
데이비드

4
"1.9.2 시작 해시 삽입 순서는 유지됩니다."
Tin Man

2
내 첫 번째 의견 다시 (재미 느낌) : 예를 들어, 해시 순서에 의존하면 1.9.2 이전의 Ruby 버전에서는 조용히 예측할 수 없게됩니다.
Jo Liss

5
OP 질문의 두 부분 중 하나조차도 대답하지 않고이 답변이 20 +1에 어떻게 도달 했습니까? "1) (OP 예)가 해시를 정렬하는 가장 좋은 방법일까요? 2) 해시 개체를 반환합니까?" 나는 +1을 부러워하지 않습니다 :) 그것은 대답을 읽은 직후에 여전히 원래의 질문으로 남아 있습니다. 또한 요점은 정렬 된 해시와 같은 것이
없다면

64

나는 항상 사용했습니다 sort_by. #sort_by출력 을 랩핑하여 Hash[]해시를 출력하도록해야합니다. 그렇지 않으면 배열의 배열을 출력합니다. 또는 이것을 달성 #to_h하기 위해 튜플 배열 에서 메소드를 실행하여 k=>v구조 (해시) 로 변환 할 수 있습니다 .

hsh ={"a" => 1000, "b" => 10, "c" => 200000}
Hash[hsh.sort_by{|k,v| v}] #or hsh.sort_by{|k,v| v}.to_h

" 숫자 값으로 루비 해시를 정렬하는 방법? " 과 비슷한 질문이 있습니다 .


8
sort_by해시를 사용 하면 배열이 반환됩니다. 다시 해시로 매핑해야합니다. Hash[hsh.sort_by{|k,v| v}]
stevenspiel

1
예, 열거 자 클래스는 해시를 내가 생각하는 배열로 해석합니다.
boulder_ruby

3
맞습니다. 정렬은 값에 있습니다 hsh.sort_by(&:last).to_h => {"b"=>10, "a"=>1000, "c"=>200000}.
캐리 스월 랜드

1
호출 to_h은 Ruby 2.1.0 이상에서만 지원됩니다.
Phrogz

1
댓글에 오타가 있습니다. 수정 :sort_by{|k,v| v}.to_h)
jitter

13

아니요, 아닙니다 (Ruby 1.9.x)

require 'benchmark'

h = {"a"=>1, "c"=>3, "b"=>2, "d"=>4}
many = 100_000

Benchmark.bm do |b|
  GC.start

  b.report("hash sort") do
    many.times do
      Hash[h.sort]
    end
  end

  GC.start

  b.report("keys sort") do
    many.times do
      nh = {}
      h.keys.sort.each do |k|
        nh[k] = h[k]
      end
    end
  end
end

       user     system      total        real
hash sort  0.400000   0.000000   0.400000 (  0.405588)
keys sort  0.250000   0.010000   0.260000 (  0.260303)

큰 해시의 경우 차이가 최대 10 배 이상 증가합니다.


12

OP에서 자신에게 가장 좋은 대답을 Hash[h.sort]했습니다. 더 많은 가능성을 원한다면 원래 해시를 적절하게 수정하여 정렬하십시오.

h.keys.sort.each { |k| h[k] = h.delete k }

1
궁금한 점 은 Ruby 1.9.3의 stackoverflow.com/a/17331221/737303 에 있는 "키 정렬"보다 약간 더 빠릅니다 .
질소

9

키로 해시 정렬 , 루비에서 해시 반환

destructuring 및 해시 번호 종류

hash.sort { |(ak, _), (bk, _)| ak <=> bk }.to_h

열거 가능

hash.sort_by { |k, v| k }.to_h

기본 동작의 해시 # 정렬

h = { "b" => 2, "c" => 1, "a" => 3  }
h.sort         # e.g. ["a", 20] <=> ["b", 30]
hash.sort.to_h #=> { "a" => 3, "b" => 2, "c" => 1 }

참고 : <Ruby 2.1

array = [["key", "value"]] 
hash  = Hash[array]
hash #=> {"key"=>"value"}

참고 :> Ruby 2.1

[["key", "value"]].to_h #=> {"key"=>"value"}

1
사용하지 않으면 v밑줄을 접두사로 hash.sort_by { |k, _v| k }.to_h
붙여야

6

루비 1.9.2를 사용하거나 자체 해결 방법을 롤링하지 않으려는 경우 ActiveSupport :: OrderedHash 가 또 다른 옵션입니다.


링크가 끊어짐
Snake Sanders

3
일부 역사가가 과거에 어떻게 이런 일이 있었는지 연구하고 싶어하는 경우 Google을 가리 키도록 링크를 수정했습니다. 그러나이 문제가 발생하면 최신 버전의 Ruby를 사용해야합니다.
eremite

0
@ordered = {}
@unordered.keys.sort.each do |key|
  @ordered[key] = @unordered[key]
end

4
루비에게 Hash # sort_by
boulder_ruby

0

나는 같은 문제가 있었고 (장비 이름으로 장비를 정렬해야 했음) 다음과 같이 해결했습니다.

<% @equipments.sort.each do |name, quantity| %>
...
<% end %>

@equipments는 모델에서 빌드하고 컨트롤러에서 반환하는 해시입니다. .sort를 호출하면 키 값을 기준으로 해시가 정렬됩니다.


-3

이전 게시물의 솔루션이 마음에 들었습니다.

나는 미니 클래스를 만들었습니다 class AlphabeticalHash. 또한 ap하나의 인수 a Hash를 입력으로 받아들이는 이라는 메소드가 ap variable있습니다. PP와 비슷 함 ( pp variable)

그러나 알파벳 목록 (키)으로 (시도하고) 인쇄합니다. Dunno 다른 사람이 이것을 사용하려면 보석으로 사용할 수 있으며 다음과 같이 설치할 수 있습니다.gem install alphabetical_hash

나에게 이것은 간단하다. 다른 사람들이 더 많은 기능이 필요하면 알려주십시오. 보석에 포함시킬 것입니다.

편집 : 크레딧은 Peter 에게 갔다. :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.