简体   繁体   English

如何将x个元组添加到列表中x次?

[英]How do I add x tuples into a list x number of times?

I have a question about tuples and lists in Haskell. 我对Haskell中的元组和列表有疑问。 I know how to add input into a tuple a specific number of times. 我知道如何将输入添加到元组中特定次数。 Now I want to add tuples into a list an unknown number of times; 现在,我想将元组添加到列表中的次数未知。 it's up to the user to decide how many tuples they want to add. 由用户决定要添加多少个元组。

How do I add tuples into a list x number of times when I don't know X beforehand? 当我事先不知道X时,如何将元组添加到列表中x次?

There's a lot of things you could possibly mean. 您可能会说很多话。 For example, if you want a few copies of a single value, you can use replicate , defined in the Prelude: 例如,如果你想有一个单一值的几个副本,您可以使用replicate ,在前奏中定义:

replicate :: Int -> a -> [a]
replicate 0 x = []
replicate n | n < 0     = undefined
            | otherwise = x : replicate (n-1) x

In ghci: 在ghci中:

Prelude> replicate 4 ("Haskell", 2)
[("Haskell",2),("Haskell",2),("Haskell",2),("Haskell",2)]

Alternately, perhaps you actually want to do some IO to determine the list. 或者,也许您实际上是想做一些IO来确定列表。 Then a simple loop will do: 然后,将执行一个简单的循环:

getListFromUser = do
    putStrLn "keep going?"
    s <- getLine
    case s of
        'y':_ -> do
            putStrLn "enter a value"
            v <- readLn
            vs <- getListFromUser
            return (v:vs)
        _ -> return []

In ghci: 在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)]

Of course, this is a particularly crappy user interface -- I'm sure you can come up with a dozen ways to improve it! 当然,这是一个特别糟糕的用户界面-我相信您可以想出很多改进方法! But the pattern, at least, should shine through: you can use values like [] and functions like : to construct lists. 但是,至少,这种模式应该会发光:您可以使用[]等值和:类的函数来构造列表。 There are many, many other higher-level functions for constructing and manipulating lists, as well. 还有很多其他许多用于构造和操作列表的高级功能。

PS There's nothing particularly special about lists of tuples (as compared to lists of other things); PS:元组列表(与其他列表相比)没有什么特别的地方; the above functions display that by never mentioning them. 以上功能通过不提及它们来显示。 =) =)

Sorry, you can't 1 . 抱歉,您不能1 There are fundamental differences between tuples and lists: 元组和列表之间存在根本差异:

  • A tuple always have a finite amount of elements, that is known at compile time . 元组总是具有有限数量的元素,这在编译时就知道 Tuples with different amounts of elements are actually different types. 具有不同数量元素的元组实际上是不同的类型。
  • List an have as many elements as they want. 列出所需的元素。 The amount of elements in a list doesn't need to be known at compile time. 列表的元素数量在编译时不需要知道。
  • A tuple can have elements of arbitrary types. 元组可以具有任意类型的元素。 Since the way you can use tuples always ensures that there is no type mismatch, this is safe. 由于可以使用元组的方式始终确保没有类型不匹配,因此这是安全的。
  • On the other hand, all elements of a list have to have the same type. 另一方面,列表中的所有元素必须具有相同的类型。 Haskell is a statically-typed language; Haskell是一种静态类型的语言。 that basically means that all types are known at compile time. 这基本上意味着在编译时所有类型都是已知的。

Because of these reasons, you can't. 由于这些原因,您不能这样做。 If it's not known, how many elements will fit into the tuple, you can't give it a type. 如果不知道元组中可以容纳多少个元素,则无法为其指定类型。

I guess that the input you get from your user is actually a string like "(1,2,3)" . 我猜您从用户那里得到的输入实际上是一个像"(1,2,3)"类的字符串。 Try to make this directly a list, whithout making it a tuple before. 尝试直接将其设为列表,而之前未使其成为元组。 You can use pattern matching for this, but here is a slightly sneaky approach. 您可以为此使用模式匹配,但这是一种稍微偷偷摸摸的方法。 I just remove the opening and closing paranthesis from the string and replace them with brackets -- and voila it becomes a list. 我只是从字符串中删除了打开和关闭状态,并用括号替换了它们,瞧,它就变成了一个列表。

tuplishToList :: String -> [Int]
tuplishToList str = read ('[' : tail (init str) ++ "]")

Edit 编辑

Sorry, I did not see your latest comment. 抱歉,我没有看到您的最新评论。 What you try to do is not that difficult. 您尝试做的并不困难。 I use these simple functions for my task: 我将以下简单功能用于任务:

  • words str splits str into a list of words that where separated by whitespace before. words str分割str成凡空格分开之前的单词列表。 The output is a list of String s. 输出是String的列表。 Caution : This only works if the string inside your tuple contains no whitespace. 注意 :仅当元组中的字符串不包含空格时,此方法才有效。 Implementing a better solution is left as an excercise to the reader. 实施更好的解决方案留给读者练习。

  • map f lst applies f to each element of lst map f lst适用f到的每个元素lst

  • read is a magic function that makes aa data type from a String. read是一个魔术函数,可以从字符串中获取数据类型。 It only works if you know before, what the output is supposed to be. 仅当您之前知道输出应该是什么时,它才起作用。 If you really want to understand how that works, consider implementing read for your specific usecase. 如果您真的想了解它是如何工作的,请考虑针对您的特定用例实现read

And here you go: 在这里,您去:

tuplish2List :: String -> [(String,Int)]
tuplish2List str = map read (words str)

1 As some others may point out, it may be possible using templates and other hacks, but I don't consider that a real solution. 1正如其他人可能指出的那样,有可能使用模板和其他技巧,但是我不认为这是一个真正的解决方案。

When doing functional programming, it is often better to think about composition of operations instead of individual steps. 在进行函数式编程时,通常最好考虑操作的组成而不是单个步骤。 So instead of thinking about it like adding tuples one at a time to a list, we can approach it by first dividing the input into a list of strings, and then converting each string into a tuple. 因此,我们不必像一次在列表中添加一个元组那样思考它,而是可以通过以下方式实现:首先将输入划分为字符串列表,然后将每个字符串转换为一个元组。

Assuming the tuples are written each on one line, we can split the input using lines , and then use read to parse each tuple. 假设每个元组写在一行上,我们可以使用lines拆分输入,然后使用read解析每个元组。 To make it work on the entire list, we use map . 为了使其适用于整个列表,我们使用map

main = do input <- getContents
          let tuples = map read (lines input) :: [(String, Integer)]
          print tuples

Let's try it. 让我们尝试一下。

$ runghc Tuples.hs
("Hello", 2)
("Haskell", 4)

Here, I press Ctrl+D to send EOF to the program, (or Ctrl+Z on Windows) and it prints the result. 在这里,我按Ctrl + D将EOF发送到程序(或在Windows上为Ctrl + Z ),它会打印结果。

[("Hello",2),("Haskell",4)]

If you want something more interactive, you will probably have to do your own recursion. 如果您想要更具交互性的内容,则可能必须自己进行递归。 See Daniel Wagner's answer for an example of that. 有关此示例,请参阅Daniel Wagner的答案

One simple solution to this would be to use a list comprehension, as so (done in GHCi): 一个简单的解决方案是使用列表理解,例如(在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]

This will work for an arbitrary number of tuples - as many as the user wants to use. 这将适用于任意数量的元组-与用户想要使用的元组一样多。

To use this in your code, you would just write: 要在您的代码中使用此代码,您只需编写:

fstMap :: Eq a => [(a,b)] -> [a]
fstMap tuplist = [fst x | x <- tuplist]

The example I gave is just one possible solution. 我给出的示例只是一种可能的解决方案。 As the name implies, of course, you can just write: 顾名思义,您当然可以这样写:

fstMap' :: Eq a => [(a,b)] -> [a]
fstMap' = map fst

This is an even simpler solution. 这是一个更简单的解决方案。

I'm guessing that, since this is for a class, and you've been studying Haskell for < 1 week, you don't actually need to do any input/output. 我猜想是因为这是一堂课,而且您学习Haskell的时间少于1周,所以您实际上不需要进行任何输入/输出。 That's a bit more advanced than you probably are, yet. 但是,这比您可能要先进一些。 So: 所以:

  • As others have said, map fst will take a list of tuples, of arbitrary length, and return the first elements. 正如其他人所说, map fst将获取一个任意长度的元组列表,并返回第一个元素。 You say you know how to do that. 您说您知道该怎么做。 Fine. 精细。

  • But how do the tuples get into the list in the first place? 但是,元组如何首先进入列表? Well, if you have a list of tuples and want to add another, (:) does the trick. 好吧,如果您有一个元组列表并想要添加另一个,则(:)可以解决问题。 Like so: 像这样:

     oldList = [("first", 1), ("second", 2)] newList = ("third", 2) : oldList 

    You can do that as many times as you like. 您可以随意执行多次。 And if you don't have a list of tuples yet, your list is [] . 而且如果您还没有元组列表,则您的列表为[]

Does that do everything that you need? 这样可以满足您的所有需求吗? If not, what specifically is it missing? 如果没有,具体缺少什么?

Edit: With the corrected type: 编辑:具有更正的类型:

Eq a => [(a, b)]

That's not the type of a function. 那不是函数的类型。 It's the type of a list of tuples. 这是元组列表的类型。 Just have the user type yourFunctionName followed by [ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)] at the prompt. 只需让用户在yourFunctionName键入yourFunctionName后跟[ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)]

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

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