주간 챌린지 #085 작업 #1::(Raku)

작업 #1 › 삼중합



제출자: Mohammad S Anwar

0보다 큰 실수 배열이 제공됩니다.

1 < a+b+c < 2와 같은 삼중항(a,b,c)이 있는지 찾는 스크립트를 작성하세요. 성공하면 1을 출력하고 그렇지 않으면 0을 출력하세요.

Example 1:

Input: @R = (1.2, 0.4, 0.1, 2.5)
Output: 1 as 1 < 1a.2 + 0.4 + 0.1 < 2

Example 2:

Input: @R = (0.2, 1.5, 0.9, 1.1)
Output: 0

Example 3:

Input: @R = (0.5, 1.1, 0.3, 0.7)
Output: 1 as 1 < 0.5 + 1.1 + 0.3 < 2


부동 대 유리수



Raku에서는 부동 소수점 값을 저장하는 두 가지 유형이 있는 것 같습니다. 실제로 우리는 대부분의 부동 소수점을 다음과 같은 유리수로 표현할 수 있습니다.

1.7 -> 10 / 17


  • Rat
  • FatRat

  • 그리고 문서에는...

    Since, unlike Rat, FatRat arithmetics do not fall back Num at some point, there is a risk that repeated arithmetic operations generate pathologically large numerators and denominators.



    그래서 쥐가 이 작업에 충분하다고 생각합니다. 쥐를 만드는 것은 간단합니다. 숫자가 정수 값이더라도 점을 추가하십시오.

    > (1.0).WHAT
    (Rat)
    > (1.7).numerator
    17
    > (1.7).denominator
    10
    > 1.Rat # or you can declare explicitly
    


    간편한 샘플



    그래서 우리는 유리수 3중항이 필요합니다. 다음 코드는 작업에 적합한 난수를 생성합니다.
  • 더 많은 0.* 값을 생성하기 위해 더 많은 0을 추가합니다. *

  • > (10..99).pick(10).map({ (|(0 xx 10), |(0..3)).pick + $_/100 })
    (3.24 0.75 0.83 0.74 0.58 0.85 1.68 0.81 0.59 0.12)
    


    삼중항의 조합



    제가 조합에 너무 집착하는 걸지도요 😂

    > my @r = (10..99).pick(10).map({ (|(0 xx 10), |(0..3)).pick + $_/100 })
    [0.23 0.1 0.13 0.56 0.81 0.71 1.4 0.79 0.16 0.52]
    > @r.combinations(3).head(3) # head() can take an argment
    ((0.23 0.1 0.13) (0.23 0.1 0.56) (0.23 0.1 0.81))
    


    삼중항의 합



    우리가 원하는 값은 1과 2 사이입니다(또는 비교하기 쉽게 1.0과 2.0).

    > @r.combinations(3).grep( -> \t { 1.0 < t.sum < 2.0 } );
    ((0.23 0.1 0.81) (0.23 0.1 0.71) (0.23 0.1 1.4) (0.23 0.1 0.79) ...
    


    좋아요.. 그 결과가 너무 많습니다. 🤪

    하나만 찾아서 💖



    인간은 욕심이 너무 많습니다. 우리는 더 많은 것을 찾고 있고 우리가 필요한 것은 하나의 가능한 대답인데도 프로세서를 고통스럽게 만듭니다.

    > @r.combinations(3).grep( -> \t { 1.0 < t.sum < 2.0 } ).head;
    ((0.23 0.1 0.81))
    


    그리고 아마도 삼중항 자체만을 얻기 위해 평평해질 것입니다.

    > @r.combinations(3).grep( -> \t { 1.0 < t.sum < 2.0 } ).head.flat;
    (0.23 0.1 0.81)
    


    잠깐만... 하지만 우리는 📔 first()

    First()는 머리가 아닙니다.



    단순히 head()를 first()로 바꾸면 ...

    > @r.combinations(3).grep( -> \t { 1.0 < t.sum < 2.0 } ).first;
    (0.23 0.1 0.81)
    


    비슷하게 보일 수 있지만 flat()이 필요하지 않으며 first()는 객체를 검색하는 방법을 제공합니다.

    > @r.combinations(3).first( -> \t { 1.0 < t.sum < 2.0 } );
    


    좋은. 아마도 아래 코드와 비슷한 일을 할 것입니다.

    > @r.combinations(3).grep( -> \t { 1.0 < t.sum < 2.0 } ).lazy.first;
    


    grep()은 조합으로 만들어진 모든 경우를 원하고 모든 경우를 확인할 때까지 완료되지 않기 때문입니다. 그리고 더 나쁜 것은 파트너에게 나쁜 습관에 대해 한꺼번에 이야기하면 끝나기도 전에 떠날 것입니다. 그렇죠? 피곤하다는 뜻입니다.
    그러나 .lazy()를 추가하면 값을 얻고자 할 때마다 평가됩니다.

    나는 grep()을 호출하기 전에 조합()이 가능한 모든 조합을 얻으려고 시도하여 .lazy()를 조합()에 추가할 수 있다고 생각합니다. 목록이 짧더라도 전체 프로그램을 약간 느리게 만들 뿐이지 아프지 않으므로 추가했습니다.

    최종 코드



    #!/usr/bin/env raku
    
    unit sub MAIN ( *@r where { @r.all ~~ Rat and @r.all > 0.0 } );
    
    @r.
    grep(* < 2.0).
    sort.
    combinations(3).
    lazy.
    first( 1.0 < *.sum < 2.0 )
    andthen say("1.0 < "
               ~ "({join(' + ', $_.List)})"
               ~ " < 2.0")
    orelse say "0";
    
    

    위의 코드는 두 번째 솔루션이며 비교를 위해 첫 번째 솔루션을 남겨 둡니다. 더 라쿠틱해 보이길래 두 번째로 찍었습니다.

    #!/usr/bin/env raku
    
    unit sub MAIN ( *@a where { @a.all ~~ Rat and @a.all > 0 } );
    
    my $triplet-it = @a.combinations(3).iterator;
    
    my $found = False;
    loop ( my $t := $triplet-it.pull-one;
        ($t =:= IterationEnd).not
        ; $t := $triplet-it.pull-one ) {
        if 1.0 < $t.sum < 2.0 {
            $found = True;
            say("1.0 < "
               ~ "({join(' + ', $t.List)})"
               ~ " < 2.0");
            last;
        }
    }
    
    say 0 unless $found;
    


    나쁘지 않다. 그렇지 않아? 명령형 또는 OOP 접근 방식일 가능성이 더 높아 보입니다.
    알았어, 그게 다야
    읽어 주셔서 감사합니다 !!
    🐪PWC🦋에서 다른 도전을 확인하십시오

    좋은 웹페이지 즐겨찾기