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


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.