Разделите число на свои цифры с помощью Haskell
Учитывая произвольное число, как я могу обрабатывать каждую цифру номера отдельно?
Edit
Я добавил базовый пример того, что может сделать Foo
.
Например, в С# я могу сделать что-то вроде этого:
static void Main(string[] args)
{
int number = 1234567890;
string numberAsString = number.ToString();
foreach(char x in numberAsString)
{
string y = x.ToString();
int z = int.Parse(y);
Foo(z);
}
}
void Foo(int n)
{
Console.WriteLine(n*n);
}
Ответы
Ответ 1
Слышали ли вы о div и mod?
Вероятно, вы захотите изменить список чисел, если хотите сначала обработать наиболее значительную цифру. Преобразование числа в строку является нарушением способа выполнения действий.
135 `div` 10 = 13
135 `mod` 10 = 5
Обобщите функцию:
digs :: Integral x => x -> [x]
digs 0 = []
digs x = digs (x `div` 10) ++ [x `mod` 10]
Или наоборот:
digs :: Integral x => x -> [x]
digs 0 = []
digs x = x `mod` 10 : digs (x `div` 10)
Это относится к 0
как к отсутствию цифр. Простая функция обертки может иметь дело с этим специальным случаем, если вы хотите.
Обратите внимание, что это решение не работает для отрицательных чисел (вход x
должен быть целым, т.е. целое число).
Ответ 2
digits :: Integer -> [Int]
digits = map (read . (:[])) . show
или вы можете вернуть его в []
:
digits :: Integer -> [Int]
digits = map (read . return) . show
или с помощью Data.Char.digitToInt:
digits :: Integer -> [Int]
digits = map digitToInt . show
точно так же, как на самом деле Даниэль, но без указания точки и использует Int, потому что цифра не должна превышать maxBound :: Int
.
Ответ 3
Используя тот же метод, который используется в вашем сообщении, вы можете сделать:
digits :: Integer -> [Int]
digits n = map (\x -> read [x] :: Int) (show n)
Смотрите в действии:
Prelude> digits 123
[1,2,3]
Помогает ли это?
Ответ 4
Вы также можете просто повторно использовать digits
из Hackage.
Ответ 5
Вы можете использовать
digits = map (`mod` 10) . reverse . takeWhile (> 0) . iterate (`div` 10)
или для обратного порядка
rev_digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)
Итерационная часть генерирует бесконечный список, делящий аргумент на каждом шаге на 10, поэтому 12345 становится [12345,1234,123,12,1,0,0..]. При этом часть занимает только интересную непустую часть списка. Затем мы отменим (если хотим) и возьмем последнюю цифру каждого номера списка.
Здесь я использовал стиль без точек, поэтому вы можете представить невидимый аргумент n по обе стороны от "уравнения". Однако, если вы хотите записать его таким образом, вы должны подставить верхний уровень .
на $
:
digits n = map(`mod` 10) $ reverse $ takeWhile (> 0) $ iterate (`div`10) n
Ответ 6
Развертывание учебника
import qualified Data.List as L
digits = reverse . L.unfoldr (\x -> if x == 0 then Nothing else Just (mod x 10, div x 10))
Ответ 7
Через понимание списка:
import Data.Char
digits :: Integer -> [Integer]
digits n = [toInteger (digitToInt x) | x <- show n]
выход:
> digits 1234567890
[1,2,3,4,5,6,7,8,9,0]
Ответ 8
Вот улучшение ответа выше. Это позволяет избежать дополнительных 0 в начале (Примеры: [0,1,0] для 10, [0,1] для 1). Используйте совпадение шаблонов для обработки случаев, когда x < 10 по-разному:
toDigits :: Integer -> [Integer] -- 12 -> [1,2], 0 -> [0], 10 -> [1,0]
toDigits x
| x < 10 = [x]
| otherwise = toDigits (div x 10) ++ [mod x 10]
Я бы поставил это в ответ на этот ответ, но у меня нет необходимых точек репутации: (
Ответ 9
Для возврата списка [Integer]
import Data.Char
toDigits :: Integer -> [Integer]
toDigits n = map (\x -> toInteger (digitToInt x)) (show n)
Ответ 10
Принятый ответ велик, но в случае отрицательных чисел он терпит неудачу, так как mod (-1) 10
оценивается до 9. Если вы хотите, чтобы это правильно обрабатывало отрицательные числа... это может быть не так, если это допустит следующий код.
digs :: Int -> [Int]
digs 0 = []
digs x
| x < 0 = digs ((-1) * x)
| x > 0 = digs (div x 10) ++ [mod x 10]
Ответ 11
Аппликатив. Pointfree. Оригами Ухоженная.
Наслаждаться:
import Data.List
import Data.Tuple
import Data.Bool
import Control.Applicative
digits = unfoldr $ liftA2 (bool Nothing) (Just . swap . ('divMod' 10)) (> 0)
Ответ 12
Мне было лень писать свои пользовательские функции, поэтому я нашел их в Google, и я был удивлен, что ни один из ответов на этом сайте не дал действительно хорошего решения - высокую производительность и безопасность ввода. Так что вот, может быть, кто-то хотел бы использовать это. В принципе:
- Это безопасный тип - он возвращает проверенный тип непустой список цифр Word8 (все вышеупомянутые решения возвращают список чисел, но это не может случиться, что мы получаем
[]
правильно?) - Этот оптимизирован по производительности с оптимизацией хвостового вызова, быстрой конкатенацией и не требует каких-либо изменений конечных значений.
- Он использует специальный синтаксис присваивания, который в связи с
-XStrict
позволяет Haskell полностью выполнять анализ строгости и оптимизировать внутренний цикл.
Наслаждаться:
{-# LANGUAGE Strict #-}
digits :: Integral a => a -> NonEmpty Word8
digits = go [] where
go s x = loop (head :| s) tail where
head = fromIntegral (x 'mod' 10)
tail = x 'div' 10
loop [email protected](r :| rs) = \case
0 -> s
x -> go (r : rs) x
Ответ 13
Принятый ответ правильный, за исключением того, что он выведет пустой список, когда ввод равен 0, однако я считаю, что вывод должен быть [0]
, когда ввод равен нулю.
И я не думаю, что это касается случая, когда ввод отрицательный. Ниже приведена моя реализация, которая решает две вышеуказанные проблемы.
toDigits :: Integer -> [Integer]
toDigits n
| n >=0 && n < 10 = [n]
| n >= 10 = toDigits (n`div`10) ++ [n`mod`10]
| otherwise = error "make sure your input is greater than 0"
Ответ 14
Я попытался использовать хвостовую рекурсию
toDigits :: Integer -> [Integer]
toDigits x = reverse $ toDigitsRev x
toDigitsRev :: Integer -> [Integer]
toDigitsRev x
| x <= 0 = []
| otherwise = x `rem` 10 : toDigitsRev (x `quot` 10)
Ответ 15
digits = reverse . unfoldr go
where go = uncurry (*>) . (&&&) (guard . (>0)) (Just . swap . (`quotRem` 10))