Подтвердить что ты не робот

Разделите число на свои цифры с помощью 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);
}
4b9b3361

Ответ 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, и я был удивлен, что ни один из ответов на этом сайте не дал действительно хорошего решения - высокую производительность и безопасность ввода. Так что вот, может быть, кто-то хотел бы использовать это. В принципе:

  1. Это безопасный тип - он возвращает проверенный тип непустой список цифр Word8 (все вышеупомянутые решения возвращают список чисел, но это не может случиться, что мы получаем [] правильно?)
  2. Этот оптимизирован по производительности с оптимизацией хвостового вызова, быстрой конкатенацией и не требует каких-либо изменений конечных значений.
  3. Он использует специальный синтаксис присваивания, который в связи с -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))