Лучший способ преобразовать фрагмент int в шестнадцатеричное значение

#go #slice

#Вперед #фрагмент

Вопрос:

У меня есть фрагмент int, содержащий только нули и единицы ( []int{1,1,1,1,0,0,0,0} )

Я хочу преобразовать строковое представление в шестнадцатеричное значение. Я конвертирую фрагмент целых чисел в фрагмент строк, а затем выполняю strconv.ParseUint преобразование.

 package main

import (
    "fmt"
    "log"
    "strconv"
    "strings"
)

func IntToString(values []int) string {
    valuesText := []string{}
    for i := range values {
        valuesText = append(valuesText, strconv.Itoa(values[i]))
    }
    return strings.Join(valuesText, "")
}

func IntSliceToHex(in []int) (string, error) {
    intString := IntToString(in)
    ui, err := strconv.ParseUint(intString, 2, 64)
    if err != nil {
        return "", err
    }
    return fmt.Sprintf("%X", ui), nil
}

func HexToBin(hex string) (string, error) {
    ui, err := strconv.ParseUint(hex, 16, 64)
    if err != nil {
        return "", err
    }
    return fmt.Sprintf("%b", ui), nil
}

func main() {
    profile := []int{1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1}

    hex, err := IntSliceToHex(profile)
    if err != nil {
        log.Fatalln(err)
    }

    bin, err := HexToBin(hex)
    if err != nil {
        log.Fatalln(err)
    }

    fmt.Println(hex, bin)
}
  

ВЫВОД: F0F 111100001111

Есть ли лучший способ сделать это?

Ответ №1:

Вы должны использовать операции сдвига битов для создания фактического числа из фрагмента, а не преобразовывать каждый бит в строку и анализировать его.

Вы также должны сохранить созданное целое число, а не преобразовывать туда и обратно в строку.

 package main

import (
    "fmt"
)

func main() {
    profile := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

    final := uint64(profile[0])
    for i := 1; i < len(profile); i   {
        final <<= 1
        final  = uint64(profile[i])
    }
    fmt.Printf("%X %bn", final, final)
    // Output: FFFFFFFFFFFF0000 1111111111111111111111111111111111111111111111110000000000000000
}
  

Примечание: final является 64-разрядным целым числом без знака и может обрабатывать profile фрагменты длиной до 64 (включительно). Для больших размеров используйте big.Int.

Комментарии:

1. Вау, это довольно аккуратно! Я не слишком знаком с операциями сдвига битов, поэтому мне придется прочитать об этом. В моем примере был сокращен фрагмент целых чисел. В моем случае это был бы фрагмент из 64 целых чисел. Я получаю совершенно другой результат. профиль:= []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} Вывод: -10000 -10000000000000000

2. Подправил пример кода. С 64 битами это 64-битное целое число без знака. Если у вас есть больше, вам нужно будет использовать что-то другое (например, big.Int )