#30일 12월 14일: 4차 코드 대전

34273 단어 elm
제 인생의 14일째입니다.
코드/데모: https://ellie-app.com/bWVYn3n7zXFa1

배경.


오늘 나는 https://www.codewars.com/에서 두 가지 난제를 해결하고 싶다
나는 11일째 되는 날 두 개를 만들었다.세 번째는 같은 1비트수를 가진 다음 2진수를 찾는 문제인데 이것이 결국 우리의 관심사가 되었다.
다음 두 개는 오늘 완성된 것으로 원형은 자바스크립트+Quokka in VS Code이다.
Elm 컴파일러처럼 CodeWars katas가 최종적으로 테스트를 통과했을 때 기분이 좋았고, 다른 사람들이 같은 문제를 어떻게 해결하는지 보는 것도 재미있었다.
  • Background
  • 1. Square every digit
  • 2. Repeat each character index+1 times

  • 3. Balanced number
  • 3.1 JavaScript solution
  • 3.2 Elm solution

  • 4. Circle of numbers
  • 4.1 JavaScript solution
  • 4.2 Elm solution
  • 4.3 One-liner
  • 5. Summary
  • 1. 각 숫자의 제곱을


    squareEveryDigit : Int -> Int
    squareEveryDigit num =
        num
            |> String.fromInt
            -- 1234 -> "1234"
            |> String.split ""
            -- "1234" -> ["1", "2", "3", "4"]
            |> List.map (\s -> String.toInt s |> Maybe.withDefault 0)
            -- ["1", "2", "3", "4"] -> [1, 2, 3, 4]
            |> List.map (\n -> n * n)
            -- [1, 2, 3, 4] -> [1, 4, 9, 16]
            |> List.map String.fromInt
            -- ["1", "4", "9", "16"]
            |> String.join ""
            -- "14916"
            |> String.toInt
            -- 14916
            |> Maybe.withDefault 0
            -- toInt returns a Maybe Int. In case the conversion doesn't work, we set 0 as the default.
    

    2. 문자당 인덱스 +1회 반복


    공백이 없는 문자열을 지정하고, 문자마다 인덱스를 +1회, 중간에 대시를 넣습니다.
    “Abc”->“A-Bb-Ccc”
    "크리스티안"-> "K-Rr-Iii-sss-Ttt-IIiii-AA-NNNN"
    upperIfIndex0 : Int -> String -> String
    upperIfIndex0 index character =
        if index == 0 then
            String.toUpper character
    
        else
            character
    
    
    repeatIndexPlus1Times : Int -> String -> String
    repeatIndexPlus1Times index character =
        List.repeat (index + 1) character
            |> List.indexedMap upperIfIndex0
            |> String.join ""
    
    
    accum : String -> String
    accum s =
        s
            |> String.toLower
            |> String.split ""
            |> List.indexedMap repeatIndexPlus1Times
            |> String.join "-"
    
    색인 변수는 List.indexedMap에서 나온다.
    앞의 두 함수는 내연적일 수 있지만, 이것은 그것을 축소된 익명 혼란으로 만들 것이다.이 밖에 index2와character2 변수명도 보기에 좋지 않다.
    accum : String -> String
    accum s =
        s
            |> String.toLower
            |> String.split ""
            |> List.indexedMap
                (\index character ->
                    List.repeat (index + 1) character
                        |> List.indexedMap
                            (\index2 character2 ->
                                if index == 0 then
                                    String.toUpper character
    
                                else
                                    character
                            )
                        |> String.join ""
                )
            |> String.join "-"
    

    3. 균형 숫자


    이것은 일련의 숫자 카타스의 첫 번째 부분이다.사용할 수 있는 Elm 버전이 없기 때문에 JavaScript로 제출한 다음 Elm에서 다시 만듭니다.
    a=가운데 숫자 왼쪽의 모든 숫자의 총계
    b=가운데 숫자 오른쪽에 있는 모든 숫자의 합계
    959->True(9==9)
    123321->True(1+2==2+1)
    123320->False(1+2!=2+0)
    다시 말하면
  • 숫자를 두 개의 목록으로 나누고 중간 숫자를 포함하지 않는다.
  • 왼쪽 목록과 오른쪽 목록의 총계는 같아야 한다.
  • 테스트는 중간 숫자가 없기 때문에 1자리나 2자리 숫자를 균형 숫자로 받아들인다.

    3.1 JavaScript 솔루션


    사실 나는 이것에 대해 매우 만족한다.
    이것들은 내가 좌우 수조를 얻어야 하는 인덱스 수다.Array.slice(start, end)start에서 end로 자르지만 end는 포함되지 않는다.
    제공하지 않으면, 그룹의 끝까지만 슬라이스됩니다.
    const a = [1, 2, 3, 4]
    const b = [1, 2, 3, 4, 5]
    
    console.log(a.slice(0, 1), a.slice(3)) // [1] [4]
    console.log(b.slice(0, 2), b.slice(3)) // [1, 2] [4, 5]
    
    Elm에서 새로 작성할 JavaScript 솔루션은 다음과 같습니다.
    function balancedNum(n) {
        const digits = String(n).split("").map(Number)
    
        if (digits.length <= 2) {
            return "Balanced"
        } else if (digits.length === 3) {
            return digits[0] === digits[2] ? "Balanced" : "Not Balanced"
        }
    
        const oneIfEven = (1 - digits.length % 2)
        const middleIndex1 = Math.floor(digits.length / 2) - oneIfEven
        const middleIndex2 = Math.ceil(digits.length / 2) + oneIfEven
    
        const left = digits.slice(0, middleIndex1)
        const right = digits.slice(middleIndex2)
    
        const sum = a => a.reduce((a, b) => a + b)
    
        return sum(left) === sum(right) ? "Balanced" : "Not Balanced"
    }
    

    3.2 Elm 솔루션


    isBalanced : Int -> String
    isBalanced n =
        -- Split digits into array
        let
            digits =
                n
                    |> String.fromInt
                    |> String.split ""
                    |> List.map String.toInt
                    |> List.map (Maybe.withDefault 0)
                    |> Array.fromList
    
            oneIfEven =
                1 - modBy 2 (Array.length digits)
    
            digitsLength =
                toFloat (Array.length digits)
    
            -- Determine where to slice into left and right arrays
            middleIndex1 =
                (digitsLength / 2 |> floor) - oneIfEven
    
            middleIndex2 =
                (digitsLength / 2 |> ceiling) + oneIfEven
    
            left =
                Array.slice 0 middleIndex1 digits
    
            right =
                Array.slice middleIndex2 (Array.length digits) digits
    
            -- Summing and comparing left and right
            resultForDigitsIs3 =
                if Array.get 0 digits == Array.get 2 digits then
                    "balanced"
    
                else
                    "not balanced"
    
            leftSum =
                Array.toList left |> List.sum
    
            rightSum =
                Array.toList right |> List.sum
    
            result =
                if digitsLength <= 2 then
                    "balanced"
    
                else if digitsLength == 3 then
                    resultForDigitsIs3
    
                else if leftSum == rightSum then
                    "balanced"
    
                else
                    "not balanced"
        in
        String.fromInt n ++ " is " ++ result
    
    목록이 아닌 그룹을 사용합니다. 왜냐하면 특정한 색인 값이 필요하기 때문입니다.
    아마도 성능 때문에 Elm 목록에 색인이 없습니까?
    부서가 Int에서 Float로 바뀌는 것은 틀림없이 이상하게 느껴질 것이다. 그러나 내가 아는 바에 의하면 이것은 성능/신뢰성 문제이다. https://github.com/elm/compiler/blob/master/hints/implicit-casts.md

    4. 숫자 링


    크기가 n인 원을 정하고 x와 반대되는 숫자를 되돌려줍니다.circleOfNumbers 10 2 반환7:

    다른 사람의 해결 방안을 고려하기 전에, 나는 나의 해결 방안이 결코 이상적이지 않다는 것을 안다. 왜냐하면 그것은 부동점 수학에 의존하기 때문이다.
    브라우저 콘솔에 0.1 + 0.2만 입력하면 내가 무슨 말을 하는지 볼 수 있습니다.:)

    4.1 JavaScript 솔루션


    다음은 기본적인 생각입니다.
  • n 각도의 수조 생성
  • const thisAngle = angles[x] 숫자 2를 반환하는 각도
  • const otherAngle = (angles[x] + 180) % 360 반대 각도
  • 로 돌아가기
  • angles.indexOf(otherAngle)는 상반된 각도의 지수를 제시했는데 우리의 예는7이다.
  • const precision = 8
    
    function circleOfNumbers(n, x) {
        const distance = 360 / n
        const angles = [...Array(n)].map((_, i) => i * distance)
            .map(n => Number(n.toFixed(precision)))
        const thisAngle = angles[x]
        const opposite = Number(
            ((thisAngle + 180) % 360)
                .toFixed(precision)
        )
    
        return angles.indexOf(opposite)
    }
    

    4.2 Elm 솔루션


    모든 전환과Maybe.withDefault는 다소 단조롭고 무미건조했지만 나는 성공했다.
    기존 indexOf 함수는 없지만 { index : Int, angle : Float } 목록을 통해 복사할 수 있습니다.
    JavaScript의 .toPrecision(n) 함수를 복사하는 데 myrho/elm-round 를 사용하고 있습니다.
    circleOfNumbers : Int -> Int -> Int
    circleOfNumbers howManyNumbers numberToCheck =
        let
            distance =
                360 / toFloat howManyNumbers
    
            angles =
                List.range 0 (howManyNumbers - 1)
                    |> List.map
                        (\index ->
                            { index = index
                            , angle = Round.round 5 (toFloat index * distance)
                            }
                        )
    
            thisAngle =
                angles
                    |> List.filter (\angle -> angle.index == numberToCheck)
                    |> List.map (\record -> record.angle)
                    |> List.head
                    |> Maybe.withDefault ""
                    |> String.toFloat
                    |> Maybe.withDefault 0
    
            otherAngleFloat =
                thisAngle + 180
    
            otherAngleOverflowString =
                Round.round 5 <| otherAngleFloat - 360
    
            otherAngleAsString =
                Round.round 5 <| thisAngle + 180
    
            otherIndex =
                angles
                    |> List.filter
                        (\this ->
                            if otherAngleFloat < 360 then
                                this.angle == otherAngleAsString
    
                            else
                                this.angle == otherAngleOverflowString
                        )
                    |> List.map (\record -> record.index)
                    |> List.head
                    |> Maybe.withDefault 0
        in
        otherIndex
    

    4.3 정기선


    여기가 내가 코드워스를 좋아하는 곳이야.테스트를 통과하고 제출할 수 있도록 복잡한 해결 방안을 제시하면 다음과 같은 문제에 직면하게 될 것이다.
    const circleOfNumbers = (n, x) => (x + n / 2) % n;
    
    너무 예뻐요.D
    현재의 지식에 따르면, 이것은 Elm에서 간단하게 복제할 수 없습니다.mod와rements 함수는 int에만 적용되기 때문입니다.
    이것은 더 간소화할 수 있지만 어쨌든 이전의 해결 방안보다 낫다.
    circleOfNumbers2 : Float -> Float -> Float
    circleOfNumbers2 n numberToFind =
        let
            num =
                numberToFind + n / 2
    
            result =
                if num > n then
                    num - n
    
                else
                    num
        in
        result
    

    5. 요약

  • 코드전 재밌어!
  • 나는 Int에서 Float 사이의 스텔스 전환을 놓쳤다.
  • 내일 만나요!

    좋은 웹페이지 즐겨찾기