Конвертировать список целых чисел в один Int (например, concat) в haskell - PullRequest
8 голосов
/ 17 декабря 2009

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

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

Ответы [ 7 ]

23 голосов
/ 17 декабря 2009

Вы можете использовать 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, давая 10 * 1 + 2 = 12. Затем это объединяется с третьим элементом список, на addDigit 12 3, в результате 10 * 12 + 3 = 123.

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

11 голосов
/ 17 декабря 2009

Вы можете concat представить строковые представления чисел, а затем read вернуть их обратно, вот так:

joiner :: [Integer] -> Integer
joiner = read . concatMap show
4 голосов
/ 01 апреля 2018

Это сработало очень хорошо для меня.

read (concat (map show (x:xs))) :: Int

Как функция читает:
Шаг 1 - преобразовать каждый int в списке в строку (map show (x:xs))
Шаг 2 - объединить каждую из этих строк вместе (concat (step 1))
Шаг 3 - читать строку как тип int read (step 2) :: Int

2 голосов
/ 17 декабря 2009

Использование read, а также intToDigit:

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

Имеет преимущество (или недостаток) в том, чтобы рвать многозначные числа.

1 голос
/ 17 декабря 2009

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

Чтобы перевернуть список, используйте reverse, чтобы получить полномочия десяти, вы можете использовать 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 -решения по существу используют правило Хорнера .

0 голосов
/ 17 декабря 2009

Я не эксперт в 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.

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


Редактировать

Спустя долгое время, я вижу, что мое решение очень грязное, так как требует перевернуть список, чтобы иметь возможность умножать каждую цифру на 10, увеличивая индекс цифры в списке, справа налево. Теперь, зная кортежи, я вижу, что гораздо лучший подход - иметь функцию, которая получает как накопленную преобразованную часть, так и остаток списка, поэтому при каждом вызове функция умножает накопленную часть на 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))
0 голосов
/ 17 декабря 2009

Что касается того, как напечатать номер, вместо

putStr n

просто попробуйте

putStr (show n)

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...