简体   繁体   English

Haskell Int 列表:[123] 到 [1,2,3]

[英]Haskell List of Int : [123] to [1,2,3]

Problem问题

i have list of int as [123,123] which i required to be as [1,2,3,1,2,3]我的 int 列表为 [123,123],我需要为 [1,2,3,1,2,3]

Current Code当前代码

i tried out the following code using recursion我使用递归尝试了以下代码

fat::[Int]->[Int]
fat [] = []
fat (a,b,c:xs) = a : b : c : fat xs

Conclusions结论

i have no idea how to acess values as '1', '2, '3 in a list [123,123] separetly我不知道如何在列表 [123,123] 中将值分别访问为“1”、“2”、“3”

I suggest to use the digs function given in this answer on each element of your list.我建议在您列表的每个元素上使用此答案中给出的digs function。 It splits an Int into a list of digits ( [Int] ).它将Int拆分为数字列表( [Int] )。 Then you just need to concatenate the resulting lists.然后你只需要连接结果列表。 This 'map and concatenate results' requirement is a perfect job for concatMap这种“映射和连接结果”要求对于concatMap来说是一项完美的工作

fat :: [Int] -> [Int]
fat = concatMap digs

This gives:这给出了:

*Main> fat [123,123]
[1,2,3,1,2,3]

Which is what you want, if I understood correctly.如果我理解正确的话,这就是你想要的。

splitNum :: Int -> [Int]
splitNum n | n <= 9     = [n]
           | otherwise  = (splitNum (n `div` 10)) ++ [n `mod` 10]

fat :: [Int] -> [Int]
fat x = concatMap splitNum x

splitNum is used to convert an Int to a [Int] by splitting it into the division by ten reminders and appending the resulting Int to the splitted rest (recursion!) splitNum 用于将 Int 转换为 [Int],方法是将其拆分为十个提醒的除法,并将生成的 Int 附加到拆分后的 rest(递归!)

Now, having a function that converts numbers into lists, go through input, apply splitNum to any Number in the inner list and concat all resulting lists (list comprehension!)现在,有一个 function 将数字转换为列表,go 通过输入,将 splitNum 应用于内部列表中的任何数字并连接所有结果列表(列表理解!)

As a new Haskell programmer I will give you my thoughts of this problem.作为一个新的 Haskell 程序员,我会给你我对这个问题的想法。 Just because I think it's good to have many alternatives, especially from different people with different experience.只是因为我认为有很多选择很好,尤其是来自不同经验的不同人。

Here's my take on the problem:这是我对这个问题的看法:

  • For each item in the list, convert that item to a char list using read.对于列表中的每个项目,使用 read 将该项目转换为 char 列表。
  • Send that char list into a function which converts each item of that list into an int, then return an list of ints.将该 char 列表发送到 function 中,该列表将该列表中的每个项目转换为一个 int,然后返回一个 int 列表。
  • Concat that list of ints into the main list.将该整数列表连接到主列表中。

To clarify:澄清:

  • [123, 234] [123, 234]
  • 123 turns into ['1', '2', '3'] 123 变成 ['1', '2', '3']
  • ['1', '2', '3'] turns into [1, 2, 3] ['1', '2', '3'] 变成 [1, 2, 3]
  • [1, 2, 3] gets concat in the main list [1, 2, 3] 在主列表中获得 concat
  • the cycle repeats for 234.循环重复 234 次。

The util function would look something like this: util function 看起来像这样:

import Char

charsToInts :: [Char] -> [Int]
charsToInts [] = []
charsToInts (x:xs) = digitToInt x : charsToInts xs

Coming from a imperative background that's how I would have solved it.来自势在必行的背景,这就是我解决它的方式。 Probably slower than just splitting the number mathematically, but I thought it would be interesting to show a alternative.可能比仅在数学上拆分数字要慢,但我认为展示一个替代方案会很有趣。

To pinpoint the problem bluntly, you have no idea how to access the digits separately because you do not understand Haskell types and pattern matching.直截了当地指出问题,您不知道如何单独访问数字,因为您不了解 Haskell 类型和模式匹配。 Let me try to help dispel some of your misconceptions.让我试着帮助消除你的一些误解。

Let's look at your list:让我们看看你的清单:

[123, 123]

What is its type ?它的类型是什么? It is clearly a list of ints, or [Int] .它显然是一个整数列表,或[Int] With lists, you can pattern match on the constructor : , known to lispers as "cons", or "list constructor".使用列表,您可以在构造函数:上进行模式匹配,lispers 将其称为“cons”或“列表构造函数”。 You put a single element on the left side of the : , and another list on the right side.您在:的左侧放置了一个元素,在右侧放置了另一个列表。 The list on the right side can be the empty list [] , which basically indicates the end of the list.右边的列表可以是空列表[] ,基本表示列表的结束。 Haskell provides "syntactic sugar" to make lists easier to write, but [123,456] actually gets desugared into 123:(456:[]) . Haskell 提供了“语法糖”以使列表更易于编写,但[123,456]实际上被脱糖为123:(456:[]) So when you pattern match (x:y:z) , you can now see that x will be assigned 123 and y will be assigned 456 .因此,当您进行模式匹配(x:y:z)时,您现在可以看到x将被分配123并且y将被分配456 z will be the rest of the list after x and y ; z将是xy之后列表的 rest ; in this case only [] is left.在这种情况下,只剩下[]

Now then, pattern matching with : works for lists .现在,与:的模式匹配适用于列表 Int s are not lists, so you can't use : to pattern match on the digits of an Int . Int不是列表,因此您不能使用:Int的数字进行模式匹配。 However, String s are lists, because String is the same as [Char] .但是, String列表,因为String[Char]相同。 So if you turn your Int into a String then you can pattern match on each character.因此,如果您将Int转换为String ,则可以对每个字符进行模式匹配。

map show [123, 123]

map applies a function to all elements of a list. map将 function 应用于列表的所有元素。 show can take an Int and turn it into a String . show可以采用Int并将其转换为String So we map show over the list of Int s to get a list of String s.所以我们map show Int的列表以获得String的列表。

["123", "123"]

Now let's turn those Strings into lists of Int s.现在让我们将这些Strings转换为Int的列表。 Since String is simply [Char] , we will again make use of map .由于String只是[Char] ,我们将再次使用map

map digitToInt "123" -- this requires that you import Data.Char (digitToInt)

This will give us [1,2,3] ;这会给我们[1,2,3] each Char in the list is turned into an Int .列表中的每个Char都变成一个Int This is what we want to do to each String in our list ["123", "123"] .这就是我们想要对列表["123", "123"]中的每个String执行的操作。 We want to map digitToInt to each String.我们希望map digitToInt到每个字符串。 But we have a list of String s.但是我们有一个String的列表。 So what do we do?那么我们该怎么办? We map it!我们map吧!

map (map digitToInt) ["123", "123"]

This will give us [[1,2,3], [1,2,3]] .这会给我们[[1,2,3], [1,2,3]] Almost what we wanted.几乎是我们想要的。 Now we just have to flatten the list of list of Int s ( [[Int]] ) into just a list of Int ( [Int] ).现在我们只需要将Int列表 ( [[Int]] ) 列表展平为Int列表 ( [Int] )。 How can we do that?我们怎么能做到这一点? Stop...Hoogle time!停止......胡歌时间! Hoogling [[a]] -> [a] we find the very first hit, concat , is exactly what we wanted.搜索[[a]] -> [a] 我们发现第一个命中concat正是我们想要的。

Let's put it all together.让我们把它们放在一起。 First we do map show to get from [Int] to [String] .首先我们做map show[Int][String] Then we do map (map digitToInt) to get from [String] to [[Int]] .然后我们做map (map digitToInt)[String][[Int]] Then we do concat to get from [[Int]] to [Int] .然后我们做concat[[Int]][Int] Then we'll just print it out!那我们就print出来吧!

import Data.Char (digitToInt)
main = print $ concat $ map (map digitToInt) $ map show $ [123, 123]

Now let's pull most of that out into a function fat现在让我们将大部分内容提取到 function fat

import Data.Char (digitToInt)
main = print $ fat [123, 123]
fat :: [Int] -> [Int]
fat xs = concat $ map (map digitToInt) $ map show $ xs

From here you could make it prettier in a few different ways.从这里你可以用几种不同的方式让它更漂亮。 concat $ map is the same as concatMap , and since we map both (map digitToInt) and show in sequence, we can merge those. concat $ mapconcatMap相同,并且由于我们 map 两者(map digitToInt)并按顺序show ,我们可以合并它们。 Also making it pointfree, we can end up with quite a terse definition:同样让它变得无意义,我们可以得到一个非常简洁的定义:

fat = concatMap (map digitToInt . show)

For the sake of completeness, I wrote it as suggested by @Ancide为了完整起见,我按照@Ancide 的建议编写了它

Implementation执行

fat' :: [Int] -> [Int]
fat' l = map (read) [[z] | z <- [x | k <- (map (show) l), x <- k]]         

Explanation :说明

{- last result -} stands for the result of the last code explained. {- last result -}代表最后解释的代码的结果。

map (show) l

This takes every element inside l and converts it to [String] .这需要l中的每个元素并将其转换为[String]

[x | k <- {- last result -}, x <- k]

While k goes through all elements inside the last result , x enumerates all character in each k .k遍历最后一个结果中的所有元素时, x枚举每个k中的所有字符。 All those are added to a list.所有这些都添加到列表中。 Now you have a String , respectively a [Char] with all digits next to each others.现在您有一个String ,分别是一个[Char] ,所有数字都彼此相邻。

[[z] | z <- {- last result -}]

This part takes each Char from the String and puts it into an empty String .这部分从String中获取每个Char并将其放入一个空String中。 Notice the [z] part!注意[z]部分! This make a list around z , which is (see above) the same as String .这会在z周围创建一个列表,这与String相同(见上文)。 Now you have a list of String with a String for each digit.现在你有一个字符串列表,每个数字都有一个字符串。

map (read) {- last result -}

This takes every item in the last result and converts it back to Int and joins them to [Int] .这将获取最后一个结果中的每个项目并将其转换回Int并将它们连接到[Int] Now you have a list of type [Int] of the wanted result.现在您有了想要结果的[Int]类型列表。

Resumé恢复

Although this implementation is possible, it's neither fast, due to all the type conversions, nor readable.尽管这种实现是可能的,但由于所有类型转换,它既不快,也不可读。

Playing around with the list monad I came up with this.玩弄列表单子我想出了这个。 Pretty much the same @Ankur's solution, except using the list monad:几乎相同的@Ankur 的解决方案,除了使用列表单子:

fat :: [Int] -> [Int]
fat is = is >>= show >>= return . digitToInt

If you had two numbers, a and b then you could turn them into a single number by doing 10*a + b.如果你有两个数字, ab ,那么你可以通过 10*a + b 将它们变成一个数字。 The same principles apply for three.同样的原则适用于三个。

It sounds like one way of doing this would be to splitEvery into lumps of three and then map a function to turn a list of three into a single number.听起来这样做的一种方法是将Every分成三个块,然后将map a function 将三个列表变成一个数字。

Does that help?这有帮助吗?

You need a function to convert Integer to string... which is obviously Show function Another function to convert a Char to Integer which is "digitToInt" in module Char You need a function to convert Integer to string... which is obviously Show function Another function to convert a Char to Integer which is "digitToInt" in module Char

And here we go:在这里我们 go:

fat::[Int]->[Int]
fat [] = []
fat ls = concat $ map (map digitToInt) (map show ls)

Please let me know if it works:)请让我知道它是否有效:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM