![](/img/trans.png)
[英]How do I return a list of tuples containing a phrase, and the number of times it appears in descending order?
[英]How do I add x tuples into a list x number of times?
我对Haskell中的元组和列表有疑问。 我知道如何将输入添加到元组中特定次数。 现在,我想将元组添加到列表中的次数未知。 由用户决定要添加多少个元组。
当我事先不知道X时,如何将元组添加到列表中x次?
您可能会说很多话。 例如,如果你想有一个单一值的几个副本,您可以使用replicate
,在前奏中定义:
replicate :: Int -> a -> [a]
replicate 0 x = []
replicate n | n < 0 = undefined
| otherwise = x : replicate (n-1) x
在ghci中:
Prelude> replicate 4 ("Haskell", 2)
[("Haskell",2),("Haskell",2),("Haskell",2),("Haskell",2)]
或者,也许您实际上是想做一些IO来确定列表。 然后,将执行一个简单的循环:
getListFromUser = do
putStrLn "keep going?"
s <- getLine
case s of
'y':_ -> do
putStrLn "enter a value"
v <- readLn
vs <- getListFromUser
return (v:vs)
_ -> return []
在ghci中:
*Main> getListFromUser :: IO [(String, Int)]
keep going?
y
enter a value
("Haskell",2)
keep going?
y
enter a value
("Prolog",4)
keep going?
n
[("Haskell",2),("Prolog",4)]
当然,这是一个特别糟糕的用户界面-我相信您可以想出很多改进方法! 但是,至少,这种模式应该会发光:您可以使用[]
等值和:
类的函数来构造列表。 还有很多其他许多用于构造和操作列表的高级功能。
PS:元组列表(与其他列表相比)没有什么特别的地方; 以上功能通过不提及它们来显示。 =)
抱歉,您不能1 。 元组和列表之间存在根本差异:
由于这些原因,您不能这样做。 如果不知道元组中可以容纳多少个元素,则无法为其指定类型。
我猜您从用户那里得到的输入实际上是一个像"(1,2,3)"
类的字符串。 尝试直接将其设为列表,而之前未使其成为元组。 您可以为此使用模式匹配,但这是一种稍微偷偷摸摸的方法。 我只是从字符串中删除了打开和关闭状态,并用括号替换了它们,瞧,它就变成了一个列表。
tuplishToList :: String -> [Int]
tuplishToList str = read ('[' : tail (init str) ++ "]")
抱歉,我没有看到您的最新评论。 您尝试做的并不困难。 我将以下简单功能用于任务:
words str
分割str
成凡空格分开之前的单词列表。 输出是String
的列表。 注意 :仅当元组中的字符串不包含空格时,此方法才有效。 实施更好的解决方案留给读者练习。
map f lst
适用f
到的每个元素lst
read
是一个魔术函数,可以从字符串中获取数据类型。 仅当您之前知道输出应该是什么时,它才起作用。 如果您真的想了解它是如何工作的,请考虑针对您的特定用例实现read
。
在这里,您去:
tuplish2List :: String -> [(String,Int)]
tuplish2List str = map read (words str)
1正如其他人可能指出的那样,有可能使用模板和其他技巧,但是我不认为这是一个真正的解决方案。
在进行函数式编程时,通常最好考虑操作的组成而不是单个步骤。 因此,我们不必像一次在列表中添加一个元组那样思考它,而是可以通过以下方式实现:首先将输入划分为字符串列表,然后将每个字符串转换为一个元组。
假设每个元组写在一行上,我们可以使用lines
拆分输入,然后使用read
解析每个元组。 为了使其适用于整个列表,我们使用map
。
main = do input <- getContents
let tuples = map read (lines input) :: [(String, Integer)]
print tuples
让我们尝试一下。
$ runghc Tuples.hs
("Hello", 2)
("Haskell", 4)
在这里,我按Ctrl + D将EOF发送到程序(或在Windows上为Ctrl + Z ),它会打印结果。
[("Hello",2),("Haskell",4)]
如果您想要更具交互性的内容,则可能必须自己进行递归。 有关此示例,请参阅Daniel Wagner的答案 。
一个简单的解决方案是使用列表理解,例如(在GHCi中完成):
Prelude> let fstMap tuplist = [fst x | x <- tuplist]
Prelude> fstMap [("String1",1),("String2",2),("String3",3)]
["String1","String2","String3"]
Prelude> :t fstMap
fstMap :: [(t, b)] -> [t]
这将适用于任意数量的元组-与用户想要使用的元组一样多。
要在您的代码中使用此代码,您只需编写:
fstMap :: Eq a => [(a,b)] -> [a]
fstMap tuplist = [fst x | x <- tuplist]
我给出的示例只是一种可能的解决方案。 顾名思义,您当然可以这样写:
fstMap' :: Eq a => [(a,b)] -> [a]
fstMap' = map fst
这是一个更简单的解决方案。
我猜想是因为这是一堂课,而且您学习Haskell的时间少于1周,所以您实际上不需要进行任何输入/输出。 但是,这比您可能要先进一些。 所以:
正如其他人所说, map fst
将获取一个任意长度的元组列表,并返回第一个元素。 您说您知道该怎么做。 精细。
但是,元组如何首先进入列表? 好吧,如果您有一个元组列表并想要添加另一个,则(:)
可以解决问题。 像这样:
oldList = [("first", 1), ("second", 2)] newList = ("third", 2) : oldList
您可以随意执行多次。 而且如果您还没有元组列表,则您的列表为[]
。
这样可以满足您的所有需求吗? 如果没有,具体缺少什么?
Eq a => [(a, b)]
那不是函数的类型。 这是元组列表的类型。 只需让用户在yourFunctionName
键入yourFunctionName
后跟[ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.