#30daysofelm 11일째: 다음 1의 2진수

25671 단어 elm
제 인생 11일째입니다.
데모: https://ellie-app.com/bVDMsDcTnXMa1
편집: 다음날 나는 elm-binary로 더 좋은 버전을 만들었다.
만약 네가 바퀴를 재발명하는 것을 좋아한다면, 오늘의 판본은 여전히 매우 좋다.

오늘 프로젝트 정보
  • About today's project
  • 0. Automatic reload with elm-live

  • 1. Int -> Next higher number with same 1 bits
  • 1.1 What are binary numbers?

  • 1.2 Converting from int to binary
  • 1.2.1 JavaScript prototyping with Quokka
  • 1.2.2 How many bits is the number?
  • 1.2.3 Generate bits
  • 1.2.4 Generate binary number
  • 1.3 Converting from binary to int

  • 1.4 Finding corresponding binary numbers
  • 1.4.1 Same number of 1 bits
  • 1.4.2 Get all numbers with the same or +1 number of bits
  • 1.4.3 Get the next binary number with the same number of 1's
  • 2. Conclusion
  • 오늘 나는 코드전의 계발을 받았다.com kata.
    사용자는 숫자를 입력한 후에 같은 1자리 숫자를 가진 다음 이진수를 찾아야 한다.
  • 입력: 42
  • 42에서 2진법으로 10101010
  • 다음에 같은 숫자 1을 가진 이진수는 44(101100)
  • 이다.
    보통 나는 가방 하나icidasset/elm-binary를 사용하지만 나 자신에게 도전을 하고 처음부터 내가 필요로 하는 기능을 실현하기로 결정했다.
    저도 비트 연산자를 어떻게 사용하는지 몰라서 오늘 대량의 재구성이 필요합니다!D

    0. elm live를 사용하여 자동으로 다시 로드
    나는 테스트가 끝나기 전에 CodeWars의 오류 메시지를 받지 않고 현지에서 나의 해결 방안을 테스트하는 것을 더욱 좋아한다.elm reactor 파일을 저장할 때 자동으로 다시 불러오는 기능이 없어서 좀 짜증납니다.
    내가 이전에 한 것은 index.html 을 만들어서 Main에서 컴파일한 자바스크립트 파일을 인용하도록 하는 것이다.엘름: https://guide.elm-lang.org/interop/
    그런 다음 프로젝트 루트 디렉토리의 두 개의 독립 터미널에서 다음을 수행합니다.
  • nodemon --exec elm make src/Main.elm --output=main.js
  • live-server
  • 그러나 오늘 나는 elm-live HTML 파일을 만들거나 Main을 컴파일하지 않아도 같은 결과를 얻을 수 있다는 것을 발견했다.엘름.
  • 설치: npm i -g elm-live
  • 프로젝트 루트 디렉토리: elm-live src/Main.elm
  • 이동 http://localhost:8000/

  • 1. Int-> 동일한 1위의 다음 숫자 이상

    1.1 이진수란 무엇입니까?
    바이너리를 읽을 때 오른쪽에서 왼쪽으로 읽습니다.
    만약 네가 6자리의 숫자를 가지고 있다면: 10101010.모든 숫자는 이전의 숫자의 두 배를 곱한다.
    (32 * 1) 
    + (16 * 0) 
    + (8 * 1) 
    + (4 * 0) 
    + (2 * 1) 
    + (1 * 0)
    
    = 42
    

    1.2 정수에서 이진법으로 전환
    0과 1로 구성된 문자열만 받아들일 수 있는 사용자 정의 형식을 만들어야 할 수도 있습니다. 아마도 가능할 것입니다.
    더 간단한 해결 방안은 비트 연산자를 사용할 수 있지만, 나는 다음에 배울 것이다.

    1.2.1 Quoka의 JavaScript 프로토타입 사용
    JavaScript를 알면 이득을 볼 수 있다Quokka installed in VS Code.
    편집기에서 이 값들을 실시간으로 볼 수 있습니다.
    오늘 같은 프로젝트에 대해 저는 자바스크립트로 원형 디자인을 하는 것을 더욱 좋아합니다. 왜냐하면 Elm으로 원형 디자인을 하면 같은 실시간 피드백을 제공하지 않기 때문입니다(제가 알기로).
    다음은 제가 사용하기 시작한 JavaScript 원형입니다.
    const n = 42
    const numberOfBits = countBits(n) // 6
    const bitsArray = generateBits(numberOfBits) // [32, 16, 8, 4, 2, 1]
    const { binaryNumber } = generateBinaryNumber(n, bitsArray) // 101010
    const cheating = (n).toString(2) // 101010
    
    function countBits(n, count = 0) {
        if (n >= 1) {
            return countBits(n / 2, count + 1)
        }
        return count
    }
    
    function generateBits(n) {
        return [...Array(n)].map((_, i) => 2 ** i).reverse()
    }
    
    function generateBinaryNumber(number, bitArray) {
        return bitArray.reduce((acc, curr) => {
            if (acc.number >= curr) {
                acc.number -= curr
                acc.binaryNumber += "1"
            } else {
                acc.binaryNumber += "0"
            }
            return acc
        }, { number, binaryNumber: "" })
    }
    

    1.2.2 숫자가 몇 자리예요?
    int를 지정합니다. 비트 목록 [8, 4, 2, 1] 을 만들고 싶지만, 우선 int가 몇 자리인지 알아야 합니다.
    countBits : Float -> Int -> Int
    countBits number count =
        if number >= 1 then
            countBits (number / 2) (count + 1)
    
        else
            count
    
    함수를 처음 호출할 때 int를 전달합니다.if문장에서 2를 제외한 결과는 부동점입니다.
    또한 Elm에 기본 매개 변수 값이 없기 때문에count 변수를 현저하게 전달해야 합니다.하지만 일부 응용 프로그램 해결 방안이 있다고 생각합니다.
    따라서 나는 반드시 이런 불공평한 방식으로 함수를 호출해야 한다. countBits (toFloat 42) 0
    1.2.3 생성 비트
    generateBits : Int -> List Int
    generateBits numberOfBits =
        List.range 0 (numberOfBits - 1)
            |> List.map (\n -> 2 ^ n)
            |> List.reverse
    
  • [0, 1, 2, 3, 4, 5]
  • [1, 2, 4, 8, 16, 32]
  • [32, 16, 8, 4, 2, 1]
  • 이것들이 있으면 우리는 마침내 이진수를 만들 수 있다.
    JavaScript에서 우리는 (42).toString(2)를 작성할 수 있지만, 이것은 더욱 재미있다D

    1.2.4 바이너리 생성
    나는 JS 솔루션이 일반적인 for 순환이 있다면 더욱 좋을 것이라고 생각한다. 그러나 reduce 매우 재미있다. Elm의 List.foldl도 마찬가지다.
    type alias BinaryNumber =
        { tempNumber : Int, binaryNumber : String }
    
    
    generateBinaryNumber : Int -> BinaryNumber
    generateBinaryNumber number =
        List.foldl
            (\currentBit accumulator ->
                if accumulator.tempNumber >= currentBit then
                    { tempNumber = accumulator.tempNumber - currentBit
                    , binaryNumber = accumulator.binaryNumber ++ "1"
                    }
    
                else
                    { accumulator | binaryNumber = accumulator.binaryNumber ++ "0" }
            )
            { tempNumber = number, binaryNumber = "" }
            (generateBits (countBits (toFloat number) 0))
    
    이곳의 단점은 내가 누적기binaryNumber 부분만 되돌아오는 것이 아니라는 것이다.내가 이렇게 할 수 있을 것 같은데?나중에 알게 될 거야.

    1.3 바이너리에서 정수로 변환
    이번에는 재밌었어!42를 예로 들면, 우리는 두 개의 목록을 조합할 수 있다. 하나는 이진 숫자이고, 다른 하나는 비트이다.
    이진 숫자:[1, 0, 1, 0, 1, 0]비트:[32, 16, 8, 4, 2, 1]그것들은 곱할 수 있다. 우리는 int를 얻을 수 있지만, 우리는 어떻게 목록 1의 모든 숫자와 목록 2의 모든 숫자를 곱합니까?
    우리가 이전에 만든 함수를 사용하면 우리는 다음과 같은 것을 얻을 수 있다.
    binaryToInt : String -> Int
    binaryToInt binaryNumber =
        let
            bits =
                generateBits <| String.length binaryNumber
    
            digits =
                String.toList binaryNumber
                    |> List.map String.fromChar
                    |> List.map String.toInt
                    |> List.map (Maybe.withDefault 0)
        in
        List.map2 (*) bits digits |> List.sum
    
    digits 변수가 좀 지루해요.
  • 우선 문자를 문자열로 변환합니다.1은 문자열로 간주되지 않습니다.
  • 그리고 우리는 모든 숫자 문자열을 int로 변환해야 한다. 이것은 매우 공평하다.
  • 그러나String.toInt가 하나Maybe Int로 되돌아오기 때문에 우리는 1000%의 파악을 해야 한다. 어떤 비inty도 전달되지 않는다Maybe.withDefault.
  • 이외에 나는 이 List.map2선에 대해 흥분을 느꼈다D

    1.4 해당하는 이진수 찾기

    1.4.1 동일한 수량의 1위
    다음 1자리 숫자와 같은 숫자를 찾기 위해서는 초기 숫자가 몇 자리인지 알아야 한다.
    그것의 2진법 표시 형식은 10101010으로 3개의 1을 포함한다.
    getNumberOf1s : String -> Int
    getNumberOf1s binaryNumber =
        binaryNumber
            |> String.toList
            |> List.map (\char -> String.fromChar char)
            |> List.filter (\c -> c == "1")
            |> List.length
    
  • ['1', '0', '1', '0', '1', '0']
  • ["1", "0", "1", "0", "1", "0"]
  • ["1", "1", "1"]
  • 3

  • 1.4.2 동일 또는 +1자리 숫자 모두 가져오기
    임의의 긴 숫자 목록을 만드는 것은 무의미하다.
    42(10101010)는 6자리이기 때문에 다음에 1이 세 번 나오는 숫자는 6자리 또는 7자리가 될 수 있다.
    봐봐101010, 너는 이것이 또 다른 6자리 숫자라는 것을 알 수 있지만, 나는 너무 피곤해서 간단하고 우아한 방법을 생각해 내지 못한다.D
    getWithNBitsOrNPlusOne : Int -> List String
    getWithNBitsOrNPlusOne number =
        let
            min =
                -1 + countBits (toFloat number) 0
    
            max =
                min + 2
        in
        List.range (2 ^ min) ((2 ^ max) - 1)
            |> List.map generateBinaryNumber
            |> List.map (\bn -> bn.binaryNumber)
    
    42살, 우리가 말하고자 하는 것은
    List.range 32 127
        |> -- [{tempNumber = ..., binaryNumber = "100000"}, ...]
        |> -- ["100000", "100001", ..., "111111"]
    
    
    elm-format 쓰지 말래요(countBits (toFloat number) 0) - 1.max = min + 1라고 하면 더 의미가 있지만 가장 낮은 숫자는 아무런 클릭도 받지 못했다. 이것은 내가 싫어하는 것이다.

    1.4.3 다음에 같은 1의 이진수를 얻는다
    getFirstMatchingBinaryNumber : Int -> String
    getFirstMatchingBinaryNumber n =
        getWithNBitsOrNPlusOne n
            |> List.filter
                (\num ->
                    (getNumberOf1s num == getNumberOf1s (generateBinaryNumber n).binaryNumber)
                        && (binaryToInt num > n)
                )
            |> List.head
            |> Maybe.withDefault ""
    
    우리는 이전부터 이진수의 범위를 얻었다.
    그런 다음 다음, 다음을 필터링(보존)합니다.
  • 동일한 수량의 1
  • 이 숫자는 n보다 크다(우리의 예 42에서)
  • 이것들이 있으면 우리는 결론을 얻을 수 있다. 다음에도 3개의 1의 숫자가 101100(44)이다.
    나는 99퍼센트가 프로그래밍을 통해 이 결론을 얻을 수 있는 더 간단한 방법이 있다고 확신한다.D

    2. 결론
  • 만약 내가 방금 사용했다면icidasset/elm-binary 이 프로그램은 훨씬 간단하고 유지보수성도 훨씬 좋을 것이다(그리고 더 정확할 수도 있다)
  • 그래도 나는 나의 많은 코드가 개선될 수 있다고 생각한다.
  • Maybe 유형은 적응하는 데 시간이 좀 걸린다.
  • 사용은 나를 즐겁게 한다.

  • Quokka+자바스크립트는 원형 디자인에 적합합니다!
  • 좋은 웹페이지 즐겨찾기