IT박스

블록이 전달 될 때 Array # sort는 어떻게 작동합니까?

itboxs 2020. 10. 21. 07:48
반응형

블록이 전달 될 때 Array # sort는 어떻게 작동합니까?


array.sort{ |x,y| block }정확히 어떻게 작동 하는지 이해하는 데 문제가 있으므로 어떻게 사용합니까?

Ruby 문서 의 예 :

   a = [ "d", "a", "e", "c", "b" ]
   a.sort                     #=> ["a", "b", "c", "d", "e"]
   a.sort { |x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

귀하의 예에서

a.sort

다음과 같다

a.sort { |x, y| x <=> y }

아시다시피, 배열을 정렬, 당신이 요소를 비교할 수 있어야합니다 (당신이 의심하는 경우, 그냥 비교를 사용하지 않고 어떤 종류의 알고리즘을 구현하려고, 아니 <, >, <=또는 >=).

제공하는 블록은 실제로 sort두 항목을 비교하기 위해 알고리즘에 의해 호출되는 함수입니다 . x하고 y항상 선택하여 입력 배열의 일부 요소 것이다 sort의 실행 중에 알고리즘.

sort알고리즘은이 비교 함수 / 블록 방법에 대한 요구 사항을 충족한다고 가정합니다 <=>:

  • x <y이면 -1 반환
  • x = y이면 0 반환
  • x> y이면 1 반환

적절한 비교 함수 / 블록을 제공하지 않으면 순서가 정의되지 않은 배열이 생성됩니다.

이제 이유를 이해해야합니다.

a.sort { |x, y| x <=> y }

a.sort { |x, y| y <=> x }

동일한 배열을 반대 순서로 반환합니다.


Tate Johnson이 추가 한 내용을 자세히 설명 <=>하기 위해 클래스에 비교 기능 구현 하면 다음과 같은 이점이 있습니다.

  1. 당신은 모듈을 포함 할 수 Comparable자동으로 다음과 같은 방법을 정의하는 것이다 클래스를 : between?, ==, >=, <, <=>.
  2. 클래스의 인스턴스는 이제 기본값 (즉, 인수없이) 호출을 사용하여 sort.

주의 <=>가 루비의 표준 라이브러리에서 의미가 어디 방법은 이미 (제공 Bignum, Array, File::Stat, Fixnum, String, Time, 등 ...).


예를 들어 정렬 할 정수 배열이있을 때 sort메서드가 요소를 적절하게 정렬하는 것은 매우 간단합니다 . sort블록이없는 일반을 사용할 때 입니다.

그러나 다른 개체를 정렬 할 때 (각각) 두 개체를 비교하는 방법을 제공해야 할 수 있습니다. class의 객체 배열이 있다고 가정 해 보겠습니다 Person. 객체 bob객체 보다 큰지 알 수 없을 것입니다 mike(즉, 클래스에 Person메서드가 <=>구현되어 있지 않음 ). 이 경우 이러한 개체를 sort메서드에 정렬 할 순서를 설명하는 코드를 제공해야합니다 . 그것이 블록 형태가 시작되는 곳입니다.

people.sort{|p1,p2| p1.age <=> p2.age}
people.sort{|p1,p2| p1.children.count <=> p2.children.count}

등. 이러한 모든 경우에 sort메서드는 동일한 방식으로 정렬합니다. 동일한 알고리즘이 사용됩니다. 차이점은 비교 논리입니다.


@OscarRyz 응답은 정렬 작동 방식에 대한 질문에 대해 많이 정리했습니다.

 { |x, y| y <=> x }

내 이해를 바탕으로 위의 블록 결과에 대한 각 비교 후 어레이의 상태가 무엇인지 여기에 제공하고 있습니다.

참고 : ruby-forum 에서 블록 매개 변수 e1, e2의 값을 인쇄하는 참조를 얻었습니다.

1.9.3dev :001 > a = %w(d e a w f k)
1.9.3dev :003 > a.sort { |e1, e2| p [e2, e1]; e2 <=> e1 }
["w", "d"]
["k", "w"]
["k", "d"]
["k", "e"]
["k", "f"]
["k", "a"]
["f", "a"]
["d", "f"]
["d", "a"]
["d", "e"]
["e", "f"]
 => ["w", "k", "f", "e", "d", "a"]

각 비교 후 런타임에 추측 된 배열 상태 :

 [e2, e1]    Comparsion Result       Array State
["w", "d"]      1                   ["w", "e", "a", "d", "f", "k"]
["k", "w"]     -1                   ["w", "e", "a", "d", "f", "k"]
["k", "d"]      1                   ["w", "e", "a", "k", "f", "d"]
["k", "e"]      1                   ["w", "k", "a", "e", "f", "d"]  
["k", "f"]      1                   ["w", "k", "a", "e", "f", "d"]    
["k", "a"]      1                   ["w", "k", "a", "e", "f", "d"]  
["f", "a"]      1                   ["w", "k", "f", "e", "a", "d"]  
["d", "f"]     -1                   ["w", "k", "f", "e", "a", "d"]  
["d", "a"]      1                   ["w", "k", "f", "e", "d", "a"]  
["d", "e"]     -1                   ["w", "k", "f", "e", "d", "a"]  
["e", "f"]     -1                   ["w", "k", "f", "e", "d", "a"] (Result)

감사,

Jignesh


<=>( self.<=>( argument )) 를 반환하는 루비 메서드입니다.

  • -1 if self <인수
  • self == 인수 인 경우 0
  • self> argument 인 경우 1

xy어레이의 항목이다. 블록이 제공되지 않으면 sort함수는를 사용하고 x<=>y, 그렇지 않으면 블록 결과에 x가 y보다 앞에 있어야 하는지를 알 수 있습니다.

array.sort{|x, y| some_very_complicated_method(x, y) }

여기서 some_very_complicated_method (x, y)가 <0 인 smth를 반환하면 x는 y보다 <인 것으로 간주됩니다.


몇 가지 기타 사항 :

  • x and y are called block parameters. The sort method basically says "I'll give you x and y, you determine whether x or y should come first, and I'll look after the boring stuff with regards to sorting"
  • <=> is called a spaceship operator.

In:

a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

what is x and y?

x and y are the elements being compared by the sorting algorithm.

This is useful to define for custom classes which element should be before the other.

For basic data ( numbers, strings , date, etc ) the natural order is predefined, but for customer element ( ie Employee ) you define who goes before who in a comparison. This block give you the chance to define that.

and what happens at y<=>x?

There, they are comparing the elements in descending order ( those with "higher" value will go first ) rather than the natural order ( x<=>y )

The <=> method stands for "compareTo" and return 0 if the elements are equivalent, or < 0 if x goes before than y or > 0 if x goes after y


I believe |x,y| y<=>x is comparing two elements at a time in descending order, as seen in: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-3C-3D-3E Say with [ "d", "a", "e", "c", "b" ], "d" and "a" appear to be compared first. Then since it is descending, both remain in the same order because d evaluates to less than a. Then d and e are evaluated. "e" is moved to "d"'s position. Without knowing the internal workings of the c code it is not possible to know where is d moved to but I figure this process continues until all elements are sorted. The c functions:

           VALUE
rb_ary_cmp(VALUE ary1, VALUE ary2)
{
    long len;
    VALUE v;

    ary2 = rb_check_array_type(ary2);
    if (NIL_P(ary2)) return Qnil;
    if (ary1 == ary2) return INT2FIX(0);
    v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2);
    if (v != Qundef) return v;
    len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2);
    if (len == 0) return INT2FIX(0);
    if (len > 0) return INT2FIX(1);
    return INT2FIX(-1);
}

참고URL : https://stackoverflow.com/questions/2637419/how-does-arraysort-work-when-a-block-is-passed

반응형