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

发布于 2024-12-09 11:33:30 字数 119 浏览 2 评论 0原文

我有一个关于 Haskell 中的元组和列表的问题。我知道如何将输入添加到元组中特定次数。现在我想将元组添加到列表中未知次数;由用户决定要添加多少元组。

当我事先不知道 X 时,如何将元组添加到列表 x 次?

I have a question about tuples and lists in 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

五里雾 2024-12-16 11:33:30

你可能意味着很多事情。例如,如果您想要单个值的几个副本,您可以使用 Prelude:

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

In ghci:

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

中定义的 replicate,或者,也许您实际上想要执行一些 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 元组列表没有什么特别之处(与其他列表相比);上述函数通过从未提及它们来显示这一点。 =)

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

In 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. 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:

*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.

P.S. There's nothing particularly special about lists of tuples (as compared to lists of other things); the above functions display that by never mentioning them. =)

來不及說愛妳 2024-12-16 11:33:30

抱歉,您不能1。元组和列表之间存在根本区别:

  • 元组始终具有有限数量的元素,这是在编译时已知的。具有不同元素数量的元组实际上是不同的类型。
  • 列表可以包含任意数量的元素。编译时不需要知道列表中元素的数量。
  • 元组可以包含任意类型的元素。由于使用元组的方式始终确保不存在类型不匹配,因此这是安全的。
  • 另一方面,列表的所有元素必须具有相同的类型。 Haskell 是一种静态类型语言;这基本上意味着所有类型在编译时都是已知的。

由于这些原因,你不能。如果不知道元组中可以容纳多少个元素,则无法为其指定类型。

我猜想您从用户那里获得的输入实际上是一个像 "(1,2,3)" 这样的字符串。尝试直接将其设为列表,而不是先将其设为元组。您可以为此使用模式匹配,但这里有一个稍微偷偷摸摸的方法。我只是从字符串中删除左括号和右括号,然后用方括号替换它们——瞧,它就变成了一个列表。

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

编辑

抱歉,我没有看到您的最新评论。你尝试做的事情并不那么困难。我使用这些简单的函数来完成我的任务:

  • words strstr 拆分为之前用空格分隔的单词列表。输出是一个String列表。 警告:仅当元组内的字符串不包含空格时,此方法才有效。实现更好的解决方案留给读者作为练习。

  • map f lstf 应用到 lst 的每个元素

  • read 是一个神奇的函数,它从字符串中生成数据类型。仅当您之前知道输出应该是什么时,它才有效。如果您确实想了解其工作原理,请考虑为您的特定用例实现 read

在这里,您可以:

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

1 正如其他一些人可能指出的那样,使用模板和其他技巧可能是可能的,但我不认为这是一个真正的解决方案。

Sorry, you can't1. 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; 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)". 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. The output is a list of Strings. 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

  • read is a magic function that makes a a data type from a String. 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.

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.

残龙傲雪 2024-12-16 11:33:30

在进行函数式编程时,通常最好考虑操作的组合而不是单个步骤。因此,我们可以通过首先将输入划分为字符串列表,然后将每个字符串转换为一个元组来实现,而不是将其视为一次将一个元组添加到列表中。

假设元组都写在一行上,我们可以使用 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)]

如果您想要更具交互性的东西,您可能必须进行自己的递归。请参阅丹尼尔·瓦格纳的回答就是一个例子。

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. To make it work on the entire list, we use 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.

[("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.

瑾兮 2024-12-16 11:33:30

一个简单的解决方案是使用列表理解,如下所示(在 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

这是一个更简单的解决方案。

One simple solution to this would be to use a list comprehension, as so (done in 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.

把昨日还给我 2024-12-16 11:33:30

我猜是这样的,因为这是一堂课,而你已经学习 Haskell 了 << 1周,你实际上不需要做任何输入/输出。这比您可能更先进一点。所以:

  • 正如其他人所说,map fst 将采用任意长度的元组列表,并返回第一个元素。你说你知道怎么做。很好。

  • 但是元组首先是如何进入列表的呢?好吧,如果您有一个元组列表并想添加另一个元组列表,(:) 就可以了。就像这样:

    oldList = [("第一个", 1), ("第二个", 2)]
    newList = ("第三", 2) : 旧列表
    

    您可以根据需要多次执行此操作。如果您还没有元组列表,则您的列表是 []

这能满足您的需要吗?如果没有,具体缺少什么?

编辑:使用更正后的类型:

Eq a => [(a, b)]

这不是函数的类型。它是元组列表的类型。只需让用户输入 yourFunctionName ,然后输入 [ ("String1", val1), ("String2", val2), ... ("LastString", lastVal)]在提示符下。

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. 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. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文