Преобразуйте список Целых чисел в один Интервал (как concat) в haskell

В значительной степени, что говорит заголовок. У меня есть список Целых чисел как так: [1,2,3]. Я хочу изменить это в на Целое число 123. Моя первая мысль была concat, но это не работает, потому что это имеет неправильный тип, я попробовал различные вещи, но обычно я только заканчиваю тем, что возвратил тот же список. Любая справка значительно ценится.

Также я нашел способ распечатать правильную вещь (putStr) кроме, я хочу, чтобы тип был Целым числом, и putStr не делает этого.

8
задан Paul 16 December 2009 в 23:13
поделиться

6 ответов

Вы можете использовать foldl для объединения всех элементов списка:

fromDigits = foldl addDigit 0
   where addDigit num d = 10*num + d

Функция addDigit вызывается foldl для добавления цифр одну за другой, начиная с самой левой.

*Main> fromDigits [1,2,3]
123

Изменить:
foldl проходит через список слева направо, добавляя элементы для накопления некоторого значения.

Второй аргумент foldl , 0 в данном случае является начальным значением процесса. На первом шаге это начальное значение комбинируется с 1 , первым элементом списка, путем вызова addDigit 0 1 . В результате получается 10 * 0 + 1 = 1. На следующем этапе эта 1 объединяется со вторым элементом списка addDigit 1 2 ,

23
ответ дан 5 December 2019 в 04:49
поделиться

You could concat the string representations of the numbers, and then read them back, like so:

joiner :: [Integer] -> Integer
joiner = read . concatMap show
11
ответ дан 5 December 2019 в 04:49
поделиться

Use read and also intToDigit:

joinInt :: [Int] -> Int
joinInt l = read $ map intToDigit l

Has the advantage (or disadvantage) of puking on multi-digit numbers.

2
ответ дан 5 December 2019 в 04:49
поделиться

Что касается того, как печатать число, вместо

putStr n

попробуйте

putStr (show n)

Причина в том, что putStr может печатать только строки. Поэтому вам нужно преобразовать число в строку перед его передачей.

Вы также можете попробовать функцию print из Prelude. Он может печатать все, что "показывается" (любой экземпляр класса Show ), а не только строки. Но имейте в виду, что print n соответствует (примерно) putStrLn (show n) , а не putStr (show n) .

0
ответ дан 5 December 2019 в 04:49
поделиться

Я не эксперт в Haskell, но это самый простой способ, который я могу придумать для решения этой проблемы, не требующий использования каких-либо других внешних функций.

concatDigits :: [Int] -> Int
concatDigits [] = 0
concatDigits xs = concatReversed (reverseDigits xs) 1

reverseDigits :: [Int] -> [Int]
reverseDigits [] = []
reverseDigits (x:xs) = (reverseDigits xs) ++ [x]

concatReversed :: [Int] -> Int -> Int
concatReversed [] d = 0
concatReversed (x:xs) d = (x*d) + concatReversed xs (d*10)

Как видите, я предположил, что вы пытаетесь объединить список цифр. Если случайно это не ваш случай, я почти уверен, что это не сработает. : (

В моем решении, прежде всего, я определил функцию с именем reverseDigits , которая меняет исходный список на противоположный. Например, с [1,2,3] на [3,2,1]

После этого я использую функцию concatReversed , которая принимает список цифр и число d, которое является результатом десятичного увеличения первой цифры в позиции списка. Если список пуст, он возвращает 0 , а если нет, возвращает первую цифру в списке, умноженную на d, плюс вызов concatReversed с передачей остальной части списка и d умножением на 10.

Надеюсь, что код говорит сам за себя, потому что я думаю, что мое плохое объяснение на английском не очень помогло.


Edit

Спустя долгое время я вижу, что мое решение очень запутанное, так как оно требует перевернуть список, чтобы иметь возможность умножать каждую цифру на 10-кратную величину индекса цифры в списке, справа налево. Теперь, зная кортежи, я вижу, что гораздо лучший подход - иметь функцию, которая получает как накопленную преобразованную часть, так и оставшуюся часть списка, поэтому при каждом вызове в in умножает накопленную часть на 10, а затем добавляет текущую цифру.

concatDigits :: [Int] -> Int
concatDigits xs = aggregate (xs, 0)
  where aggregate :: ([Int], Int) -> Int
        aggregate ([], acc) = acc
        aggregate (x:xs, acc) = aggregate (xs, (acc * 10 + x))
-1
ответ дан 5 December 2019 в 04:49
поделиться

Другая идея - сказать: последняя цифра считается за 1, предпоследняя - за 10, цифра перед ней - за 100. и т. д. Итак, чтобы преобразовать список цифр в число, вам нужно перевернуть его (чтобы начать с конца), умножить цифры вместе с соответствующими степенями десяти и сложить результат вместе.

Чтобы перевернуть список , используйте обратный , чтобы получить степень десяти, вы можете использовать iterate (* 10) 1 (попробуйте в GHCi или Hugs!), для умножения соответствующих цифр двух списков используйте zipWith (*) и чтобы сложить все вместе, используйте sum - это действительно помогает знать несколько библиотечных функций! Сложив биты вместе, вы получите

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

Пример оценки:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

Однако это решение работает медленнее, чем решения с foldl , из-за вызова reverse и поскольку вы наращиваем эти силы десяти только для того, чтобы снова использовать их напрямую. С другой стороны, этот способ построения чисел ближе к тому, как люди обычно думают (по крайней мере, я!), В то время как foldl -решения, по сути, используют правило Хорнера . 1118512] для умножения соответствующих цифр двух списков используйте zipWith (*) , а чтобы сложить все вместе, используйте sum - это действительно помогает знать несколько библиотечных функций! Сложив биты вместе, вы получите

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

Пример оценки:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

Однако это решение медленнее, чем решения с foldl , из-за вызова reverse и поскольку вы наращиваем эти силы десяти только для того, чтобы снова использовать их напрямую. С другой стороны, этот способ построения чисел ближе к тому, как люди обычно думают (по крайней мере, я!), В то время как foldl -решения, по сути, используют правило Хорнера . 1118512] для умножения соответствующих цифр двух списков используйте zipWith (*) , а чтобы сложить все вместе, используйте sum - это действительно помогает знать несколько библиотечных функций! Сложив биты вместе, вы получите

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

Пример оценки:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

Однако это решение работает медленнее, чем решения с foldl , из-за вызова reverse и поскольку вы наращиваем эти силы десяти только для того, чтобы снова использовать их напрямую. С другой стороны, этот способ построения чисел ближе к тому, как люди обычно думают (по крайней мере, я!), В то время как foldl -решения, по сути, используют правило Хорнера . 1118512] вы получите

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

Пример оценки:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

Однако это решение медленнее, чем решения с foldl , из-за вызова reverse и поскольку вы наращиваете те степени десяти только для того, чтобы использовать их напрямую снова. С другой стороны, этот способ построения чисел ближе к тому, как люди обычно думают (по крайней мере, я!), В то время как foldl -решения, по сути, используют правило Хорнера . 1118512] вы получите

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

Пример оценки:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

Однако это решение медленнее, чем решения с foldl , из-за вызова reverse и поскольку вы наращиваете те степени десяти только для того, чтобы использовать их напрямую снова. С другой стороны, этот способ построения чисел ближе к тому, как люди обычно думают (по крайней мере, я!), В то время как foldl -решения, по сути, используют правило Хорнера . 1118512]

1
ответ дан 5 December 2019 в 04:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: