tags:

views:

423

answers:

4

I have the following Int lists:

t1 = [1000, 1001, 1002, 1003, 1004]
t2 = [2000, 2001, 2002]
t3 = [3000, 3001, 3002, 3003]

The lists size are variable, they are not just 3 like in this example. They can have 1 element or many more. Then I have this:

tAll = [t1, t2, t3]

I need a function that "turns" tAll into something like this:

[[1, 1000, 2000, 3000],
[2, 1001, 2001, 3001],
[3, 1002, 2002, 3002],
[4, 1003, 0, 3003], 
[5, 1004, 0, 0]]

Is there an easy way to do this?

EDIT: I'm sorry, I posted this in a hurry and it was not exactly what I wanted. I updated the code above...

+1  A: 

zip3 will turn the 3 lists into a single list of triples. If you want length-three lists instead, you can use zipWith3 (\a b c -> [a,b,c])

If you want something different in detail (as in your updated request), you'll have to roll your own. I'd say, put your termination condition first, then deal with the general case. You should have two auxiliary functions -- one to fix the values the way you want (e.g., "head_or_zero"), and one to handle input lists that have terminated (e.g., "tail_or_nil"):


fix _ [] [] [] = []
fix i as bs cs = [i, hoz as, hoz bs, hoz cs]:fix (i+1) (ton as) (ton bs) (ton cs) where
    hoz [] = 0
    hoz x:xs = x
    ton [] = []
    ton x:xs = xs
comingstorm
+2  A: 

Well, this is the Haskell beginner's way to write it, but since it's doing explicit recursion there is probably a better way. :-)

head0 [] = 0
head0 xs = head xs

tail0 [] = []
tail0 xs = tail xs

nreorder n ts
  | all null ts = []
  | otherwise   = (n : map head0 ts) : nreorder (n+1) (map tail0 ts)

And nreorder 1 tAll prints the list you want. You can avoid those indices by doing the following instead:

reorder ts
  | all null ts = []
  | otherwise   = (map head0 ts) : reorder (map tail0 ts)

so that reorder tAll = [[1000,2000,3000],[1001,2001,3001],[1002,2002,3002],[1003,0,3003],[1004,0,0]], and (slightly cleaned up thanks to mattiast):

nreorder ts = zipWith (:) [1..] (reorder tAll)

so that nreorder tAll prints the list you want.

ShreevatsaR
I find it confusing... Isn't there a way to do it without the extra head/tail functions and/or without the "all null ts = []" thing?
Nazgulled
The extra head/tail functions are the easiest way to express what you want to do with an empty list. Get used to auxiliary functions if you want to use Haskell.The "all null ts" thing is useful for handling an arbitrary number of input lists, instead of exactly 2, 3 or 42 lists...
comingstorm
The "all null ts" means whether "all the lists in ts are empty". Think of what you need to do at the last steps, where after "nreorder 4 [[1003,1004],[],[3003]]", and "nreorder 5 [[1004],[],[]]" it comes to "nreorder 6 [[],[],[]]".
ShreevatsaR
And er, you shouldn't be reading it as "all null ts = []" -- maybe you need to get familiar with the guard syntax? http://en.wikipedia.org/wiki/Guard_%28computing%29
ShreevatsaR
+2  A: 
ja
Oops, I hope I didn't give away a homework answer... But given that his first version of the question was something entirely different, and his previous questions seem to have been about Html stuff, this is more likely to be a problem from "real life".
ShreevatsaR
This is still about the Html stuff, I just made a generic example to be easier to understand and I'll adapt it later. Actually this is for a project I have to turn in tomorrow, but this problem in particular is something I want to do, it's not part of any requested feature.
Nazgulled
Nice. How much time does it take, BTW? It seems (because of the !! and ++) that something is quadratic where it can be linear, but I'm not really sure how to reason in the face of lazy evaluation.
ShreevatsaR
Is (!!) linear or constant time? I can see it being linear, stepping thru the list, but, with boxing, it could be const-just mult to get the offset. At any rate, some quick timings show rotate 5 times faster than nreorder (5sec vs 1sec on (take 10e5 list) under ghc 6.8.2). I might profile it.
ja
(!!) is linear. But I don't know if ghc can figure out all the successive (!!)s in total linear time. And er... do you mean "slower"? It seems that rotate is linear in the number of lists but quadratic in the lengths: O(mn^2) for m lists of length n, while nreorder is O(mn). Because of (++) I guess.
ShreevatsaR
+4  A: 

Here is a one-liner for you, if you're still interested:

zipWith (:) [1..] $ take (maximum $ map length tAll) 
                         (transpose (map (++repeat 0) tAll))

edit: OK, it's better to write it with two lines :)

mattiast
That is some beautiful code right there!
Daniel W
Very nice, +1. This is the best solution! Contrary to what I said in my previous comment, this is linear in both the length of each list and the number of lists :-)
ShreevatsaR