Поскольку он возвращает кортежи (и может использовать тонны памяти), трюк zip(*zipped)
кажется мне более умным, чем полезным.
Вот функция, которая на самом деле даст вам обратный zip.
def unzip(zipped):
"""Inverse of built-in zip function.
Args:
zipped: a list of tuples
Returns:
a tuple of lists
Example:
a = [1, 2, 3]
b = [4, 5, 6]
zipped = list(zip(a, b))
assert zipped == [(1, 4), (2, 5), (3, 6)]
unzipped = unzip(zipped)
assert unzipped == ([1, 2, 3], [4, 5, 6])
"""
unzipped = ()
if len(zipped) == 0:
return unzipped
dim = len(zipped[0])
for i in range(dim):
unzipped = unzipped + ([tup[i] for tup in zipped], )
return unzipped
Слышали ли вы о 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
должен быть целым, т. Е. Целое число).
Через понимание списка:
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]
Используя тот же метод, который используется в вашем сообщении, вы можете сделать:
digits :: Integer -> [Int]
digits n = map (\x -> read [x] :: Int) (show n)
См. его в действии:
Prelude> digits 123
[1,2,3]
Помогает ли это?
Для возврата списка [Integer]
import Data.Char
toDigits :: Integer -> [Integer]
toDigits n = map (\x -> toInteger (digitToInt x)) (show n)
toDigits = map (toInteger . digitToInt) . show
– kibin
16 August 2015 в 17:20
Вот улучшение ответа выше. Это позволяет избежать дополнительных 0 в начале (Примеры: [0,1,0] для 10, [0,1] для 1). Используйте совпадение шаблонов для обработки случаев, когда x & lt; 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]
Я бы поставил это в ответ на этот ответ, но у меня нет необходимых точек репутации: (
Вы также можете просто повторно использовать digits
из Hackage.
Учебник разворачивается
import qualified Data.List as L
digits = reverse . L.unfoldr (\x -> if x == 0 then Nothing else Just (mod x 10, div x 10))
import Data.Bool.bool
, вы можете сделать его еще более сексуальным, как unfoldr (\x -> bool Nothing (Just (rem x 10, div x 10)) (x > 0))
– Redu
12 October 2017 в 15:34
digits d = reverse . unfoldr (\x -> bool (Just $ swap $ divMod x 10) Nothing (x == 0)) $ abs d
. Необходимые импорт: Data.List (unfoldr)
, Data.Tuple (swap)
, Data.Bool (bool)
– Matthias Braun
13 March 2018 в 21:04
Вы можете использовать
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
Принятый ответ правильный, за исключением того, что он выдает пустой список, когда ввод равен 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"
digits = reverse . unfoldr go
where go = uncurry (*>) . (&&&) (guard . (>0)) (Just . swap . (`quotRem` 10))
quotRem
разделяет последнюю цифру в основном и возвращает кортеж цифры и остальных.
– Blank Chisui
2 November 2017 в 16:28
Принятый ответ велик, но не работает в случае отрицательных чисел, так как 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]
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
так же, как на самом деле Daniel , но бессмысленно и использует Int, потому что цифра не должна превышать maxBound :: Int
.
digitToInt
, вероятно, все равно лучше, а :[]
для меня несколько более очевидна. э-э, я отредактирую его. Я понятия не имею, откуда чист.
– muhmuhten
19 October 2010 в 23:00
pure
и да, это будет эквивалентно. (требуется эквивалент.)
– muhmuhten
18 August 2014 в 01:27
Аппликативный . Pointfree . Оригами . Аккуратно.
Наслаждайтесь:
import Data.List
import Data.Tuple
import Data.Bool
import Control.Applicative
digits = unfoldr $ liftA2 (bool Nothing) (Just . swap . (`divMod` 10)) (> 0)
Я пытался сохранить хвостовую рекурсию
toDigits :: Integer -> [Integer]
toDigits x = reverse $ toDigitsRev x
toDigitsRev :: Integer -> [Integer]
toDigitsRev x
| x <= 0 = []
| otherwise = x `rem` 10 : toDigitsRev (x `quot` 10)