【发布时间】:2013-03-11 14:20:26
【问题描述】:
我必须在 Haskell 元组中获取第 n 个元素。元组是这样的: (3,5,"String1","String2","String3","String4","String5","String6","String7","String8","String9","String10")。你能给我一个想法,以便我可以解决这个问题吗? 谢谢。
【问题讨论】:
我必须在 Haskell 元组中获取第 n 个元素。元组是这样的: (3,5,"String1","String2","String3","String4","String5","String6","String7","String8","String9","String10")。你能给我一个想法,以便我可以解决这个问题吗? 谢谢。
【问题讨论】:
你可以通过模式匹配来做到这一点。就像你可以匹配一个二值或三值元组一样,你也可以匹配一个十值元组。
let (_, _, _, _, _, _, _, _, _, x, _, _) = tuple in x
但是,您可能不想要这样做。如果您试图从元组中获取第 n 个值,那么您几乎肯定使用了错误的类型。在 Haskell 中,不同长度的元组是不同的类型——它们从根本上是不兼容的。就像Int 和String 不同一样,(Int, Int) 和(Int, Int, Int) 也完全不同。
如果您想要一个可以获取第 n 个元素的数据类型,您需要一个列表:类似于[String]。对于列表,您可以使用 !! 运算符进行索引(从 0 开始),因此您可以这样做:
myList !! 9
获取第 10 个元素。
鉴于你的例子,我怀疑你想要一个像 (Int, Int, [String]) 这样的类型,而不是一个巨大的元组。这将使您有两个数字和任意数量的字符串;您可以使用上面的!! 运算符按索引获取字符串。
【讨论】:
_ 替换为名称中的_ 来获取值,这意味着您不关心该位置的值。
!! 不是一个好主意,因为它是部分的,而且建议使用列表来按索引访问项目更糟糕。另一方面,Vector's !? 很好。
您可能知道也可能不知道 fst 和 snd 仅适用于 2 元素元组,即
fst' (a,b) = a
据我所知,你必须自己写
get5th (_,_,_,_,a,_,_,_,_,_) = a
如您所见,您可能想要定义自己的类型。
【讨论】:
【讨论】:
我在寻找相同问题的解决方案时看到了您的问题。我读过“!!”运营商是一个糟糕的解决方案。我想到了一个解决方案:
例如,如果列表中的每个元组都有三个元素,则可以这样做:
nTuple :: [(a, a, a)] -> Integer -> Integer -> [a]
nTuple list group position = [ fst x | x <- (concat [ fst x | x <- (zip [(zip[t1, t2, t3][0..]) | (t1, t2, t3) <- list ] [0..]) , snd(x) == group ]) , snd(x) == position]
现在,一些测试用例:
*Main> nTuple [("l","m","n"),("o","p","q"),("r","s","t")] 2 1
["s"]
*Main> nTuple [("l","m","n"),("o","p","q"),("r","s","t")] 0 2
["n"]
*Main> nTuple [("l","m","n"),("o","p","q"),("r","s","t")] 100 2
[]
*Main> nTuple [("l","m","n"),("o","p","q"),("r","s","t")] 2 100
[]
上述函数的逐步解释:
1.拆分元素并放入索引:
[ zip[t1,t2,t3][0..] | (t1,t2,t3) <- [("l","m","n"),("o","p","q"),("r","s","t")]]
result: [[("l",0),("m",1),("n",2)],[("o",0),("p",1),("q",2)],[("r",0),("s",1),("t",2)]]
2.为每个列表放置一个索引。现在我们在每个组中都有组和位置。
zip [[("l",0),("m",1),("n",2)],[("o",0),("p",1),("q",2)],[("r",0),("s",1),("t",2)]] [0..]
result: [([("l",0),("m",1),("n",2)],0),([("o",0),("p",1),("q",2)],1),([("r",0),("s",1),("t",2)],2)]
3.我们可以选择一个组。例如组号 1(第一组是 0)与 "snd(x)==1"
[ fst x | x <- [([("l",0),("m",1),("n",2)],0),([("o",0),("p",1),("q",2)],1),([("r",0),("s",1),("t",2)],2)] , snd(x) == 1 ]
result: [[("o",0),("p",1),("q",2)]]
4.我们有一个列表列表。在单个元组列表中连接元组时
concat [[("o",0),("p",1),("q",2)]]
result: [("o",0),("p",1),("q",2)]
5.最后,我们通过索引得到一个元素。在这个例子中,我们得到了第二个元素(第一个元素是“0”位置)
[ fst x | x <- [("o",0),("p",1),("q",2)] , snd(x) == 2]
result ["q"]
【讨论】:
如果您只需要每个元组执行一次,并且一次需要所有元素,则可以简单地使用
let (x, y, s1, s2, s3, s4, s5, s6, s7, s8) = someTuple
in ...
并直接使用这些值。
【讨论】:
我认为你最好使用记录类型,例如:
data MyRec = MyRec {myrecfoo::Double, myrecbar::String, myrecbaz::String}
然后使用记录访问器:
baz = myrecbaz rec
但如果您想要/需要坚持使用元组并且字段少于 20 个,您可以使用 Control.Lens.Tuple
【讨论】: