代码之家  ›  专栏  ›  技术社区  ›  Greg B

用haskell将数字拆分为数字

  •  30
  • Greg B  · 技术社区  · 14 年前

    给定一个任意的数字,我如何单独处理数字的每个数字?

    编辑 我添加了一个基本的例子 Foo 可能会。

    例如,在C中,我可能会这样做:

    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);
    }
    
    15 回复  |  直到 6 年前
        1
  •  77
  •   David Cain    12 年前

    你听说过吗 div and 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
  •  19
  •   Quinn Wilson    6 年前
    digits :: Integer -> [Int]
    digits = map (read . (:[])) . show
    

    或者你可以把它放回 [] :

    digits :: Integer -> [Int]
    digits = map (read . return) . show
    

    或者,使用data.char.digitpoint:

    digits :: Integer -> [Int]
    digits = map digitToInt . show
    

    和丹尼尔的一样,不过是免费的,使用int,因为一个数字不应该超过 maxBound :: Int .

        3
  •  13
  •   hammar Muthumani    14 年前

    你也可以重复使用 digits 来自Hackage。

        4
  •  12
  •   Daniel    14 年前

    使用你的帖子中使用的相同技术,你可以做到:

    digits :: Integer -> [Int]
    digits n = map (\x -> read [x] :: Int) (show n)
    

    见效:

    Prelude> digits 123
    [1,2,3]
    

    这有帮助吗?

        5
  •  9
  •   Landei    14 年前

    你可以使用

    digits = map (`mod` 10) . reverse . takeWhile (> 0) . iterate (`div` 10)
    

    或者相反的顺序

    rev_digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)
    

    迭代部分生成一个无限列表,将每一步中的参数除以10,因此12345变为[123451234123,12,1,0,0..]。takewhile部分只接受列表中有趣的非空部分。然后我们反转(如果我们想的话)并取列表中每个数字的最后一位。

    我在这里使用了无点样式,所以你可以想象在“等式”的两边有一个看不见的论点。但是,如果你想这样写,你必须替换顶层 . 通过 $ :

    digits n = map(`mod` 10) $ reverse $ takeWhile (> 0) $ iterate (`div`10) n
    
        6
  •  9
  •   jon_darkstar    14 年前

    教科书展开

    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
  •  2
  •   Andrew    9 年前

    通过列表理解:

    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
  •  2
  •   granmoe    9 年前

    下面是对上述答案的改进。这样可以避免在开始时出现额外的0(例如:10为[0,1,0],1为[0,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
  •  2
  •   Scarabyte    7 年前

    Applicative . Pointfree . Origami . 整洁的

    享受:

    import Data.List                                                                
    import Data.Tuple                                                               
    import Data.Bool                                                                
    import Control.Applicative 
    
    digits = unfoldr $ liftA2 (bool Nothing) (Just . swap . (`divMod` 10)) (> 0) 
    
        10
  •  1
  •   Duda Dornelles    10 年前

    返回[整数]的列表

    import Data.Char
    toDigits :: Integer -> [Integer]
    toDigits n = map (\x -> toInteger (digitToInt x)) (show n)
    
        11
  •  1
  •   michael.schuett    9 年前

    接受的答案很好,但在负数的情况下失败,因为 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]
    
        12
  •  1
  •   Wojciech Danilo    6 年前

    我懒得写我的自定义函数,所以我在谷歌上搜索了它,我很惊讶这个网站上的答案都没有提供一个真正好的解决方案高性能和类型安全。所以在这里,也许有人想用它。基本上:

    1. 它是类型安全的-它返回一个由单词8数字组成的类型检查的非空列表(上面所有的解决方案都返回一个数字列表,但我们无法得到 [] 对吗?)
    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 s@(r :| rs) = \case
            0 -> s
            x -> go (r : rs) x
    
        13
  •  0
  •   Leonard Ge    7 年前

    接受的答案是正确的,除了当输入为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
  •  -1
  •   Wessel Badenhorst    9 年前

    我试图继续使用尾部递归

    toDigits :: Integer -> [Integer]
    toDigits x = reverse $ toDigitsRev x
    
    toDigitsRev :: Integer -> [Integer]
    toDigitsRev x
        | x <= 0 = []
        | otherwise = x `rem` 10 : toDigitsRev (x `quot` 10)
    
        15
  •  -2
  •   Li Chanjuan    9 年前
    digits = reverse . unfoldr go
      where go = uncurry (*>) . (&&&) (guard . (>0)) (Just . swap . (`quotRem` 10))