How to get nth element from a 10-tuple in Haskell?
Asked Answered
D

7

34

I have to get nth element in a Haskell tuple. And the tuples are like this : (3,5,"String1","String2","String3","String4","String5","String6","String7","String8","String9","String10"). Can you give me an idea so that I can solve this problem? Thanks.

Dourine answered 21/3, 2013 at 21:15 Comment(0)
E
49

As you may or may not know fst and snd only work for 2-element tuples ie

fst' (a,b) = a

You have to write you own as far as I know

get5th (_,_,_,_,a,_,_,_,_,_) = a

As you can see you may want to define your own type.

Esophagus answered 21/3, 2013 at 21:23 Comment(0)
M
48

You could do it with pattern matching. Just like you can match against a two- or three-value tuple, you can match against a ten-value tuple.

let (_, _, _, _, _, _, _, _, _, x, _, _) = tuple in x

However, chances are you don't want to do that. If you're trying to get the nth value out of a tuple, you're almost definitely using the wrong type. In Haskell, tuples of different lengths are different types--they're fundamentally incompatible. Just like Int and String are different, (Int, Int) and (Int, Int, Int) are also completely different.

If you want a data type where you can get the nth element, you want a list: something like [String]. With lists, you can use the !! operator for indexing (which starts at 0), so you could just do:

myList !! 9

to get the 10th element.

Given your example, I suspect you want a type like (Int, Int, [String]) rather than a gigantic tuple. This will let you have two numbers and any number of strings; you can get the strings by index using the !! operator as above.

Momently answered 21/3, 2013 at 21:23 Comment(6)
Thank you very much for such a good answer. I have an input as a 10-tuple and I have to get the elements from it. I want to learn if it is easy to divide the tuple to 2 different lists : first a list of 2 integers and a list of 8 strings?Dourine
@user1954132: To do that, you'd have to pattern match against the tuple anyhow. If you can't get the input as a different type, you'll have to pattern match against it at some point, which is going to be a bit awkward. You can get the values by replacing the _ in my example with names--_ in a pattern just means that you don't care about the value at that position.Momently
It's not a good idea to suggest using !!, because it's partial, and it's even worse to suggest using a list for accessing an item by index. Vector's !? on the other hand is fine.Sverdlovsk
Yes if you want a structure for storing indexed data, List is not the right structure. It is not meant for indexing and is more akin to a control flow structure. Vector or Arrays are meant for this --- just like in every other language.Dubois
What if I want to handle vectors with different type, and call its element easily? .. Isn't there a cleaner way in Haskell?Grenoble
@Grenoble that's a deep question on its own, worth asking separately. (It's probably already addressed somewhere on SO.) Unsatisfyingly, the comment-length answer is that it depends on exactly what you're trying to do.Momently
B
26

You might like to use the selection functions from the tuple package.

Bravar answered 21/3, 2013 at 22:32 Comment(0)
R
6

If you only need to do this once per tuple, and you need all the elements at once, you can simply use

let (x, y, s1, s2, s3, s4, s5, s6, s7, s8) = someTuple
in ...

and use the values directly.

Romie answered 21/2, 2017 at 13:33 Comment(0)
V
1

I think you better use a record type, like:

data MyRec = MyRec {myrecfoo::Double, myrecbar::String, myrecbaz::String}

and then use the record accessors:

baz = myrecbaz rec

But if you want/need to stick with tuples and have less than 20 fields you can use Control.Lens.Tuple

Viscus answered 21/1, 2021 at 5:45 Comment(0)
A
0

I have seen your question when i was searching a solution for the same problem. I have read the "!!" operator is a bad solution. I have thought a solution:

For example, if you have three elements for each tuple in your list you can do this:

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]

Now, some test cases:

*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
[]

Explication step by step of the above function:

1.Split elements and put an index:

[ 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.For each list put an index. Now we have groups and positions within each group.

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.We can select a group. For example the group number 1 (first group is the 0) with "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.We have a list of lists. Whe concatenate tuples in a single list of tuples

concat [[("o",0),("p",1),("q",2)]]

result: [("o",0),("p",1),("q",2)]

5.Finally, we get a element by index. In this example we get the 2nd element (first element is the "0" position)

[ fst x | x <- [("o",0),("p",1),("q",2)] , snd(x) == 2]

result ["q"]
Angelenaangeleno answered 24/5, 2016 at 18:23 Comment(5)
What does this have to do with the question?Tound
Does the user want to obtain an element after giving the position of that element? Please, read my response slowly. I do not understand your negative vote. My "nTuple" function does that user wants, I think. :/Angelenaangeleno
The question has to do with extracting an element from a single large tuple. Your answer has something to do with a list of tuples.Tound
I tried to give a generic solution for one or more tuples. I'm new to Stackoverflaw. Next time I'll try to get to the point. Sorry.Angelenaangeleno
It's perfectly fine to take a circuitous or extra-general approach. But you always need to come back around to show how it answers the question it solves the poser's problem. In this case, I don't think it does. Also, while it's great to work from the general to the specific, it's also important to work from the small to the large. I think any good solution for lists of tuples will be built from one for individual tuples. In fact, a solution for lists of tuples is probably not what you want if you know exactly how many tuples you have!Tound
G
0

say for example you have 4 directions, West East North and South, and you want to extract the value of each of those ( let's suppose that the tuple has the direction in this order W E N S)

Coord::Int ->Int ->Int ->Int ->(Int,Int,Int,Int)
Coord a b c d = (a,b,c,d)

myCoord = Coord 0 10 0 5

if you try and extract the values like this

let (W,E,N,S)= myCoord

your compiler will scream at you, to counter that, you'll have to have getters for each of your values ( Yes individually)

getW (W,_,_,_) = W
getE (_,E,_,_) = E
getN (_,_,N,_) = N
getS (_,_,_,S) = S

and there you go !

Googins answered 19/3 at 23:49 Comment(1)
Welcome to StackOverflow. I'm afraid this is not a useful answer though: 1. it's unclear what you're actually explaining here and what it provides that the other answers don't contain already 2. this is not legal Haskell code. Variables can't be uppercase.Beers

© 2022 - 2024 — McMap. All rights reserved.