How to zip two different sized lists?

683 views
Skip to first unread message

Bill Lear

unread,
Feb 2, 2011, 3:00:18 PM2/2/11
to scala...@googlegroups.com
I have two lists:

val a = (1, 2)
val b = (3, 4, 5)

I would like to create a single list of lists:

( (1,3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5) )

Is there a simple/elegant way to do this in scala?


Bill

HamsterofDeath

unread,
Feb 2, 2011, 3:07:21 PM2/2/11
to scala...@googlegroups.com
(part of my richtraversable, does exactly what you want)

/**
* a view of an n*m-combination of all elements, probably Ordered[_]
like this: t1a -> t2a, t1a -> t2b, t1a -> t2c, t1b -> t2a, t1b -> t2b
and so on
*/
def *[T2](other: Traversable[T2]): Traversable[(T, T2)] = {
t.view.flatMap(e => other.map(e -> _))

Nate Nystrom

unread,
Feb 2, 2011, 3:09:02 PM2/2/11
to Bill Lear, scala...@googlegroups.com
Hi Bill,

That's not a zip, but rather a cartesian product. You can create it using a for comprehension:

scala> for (x <- List(1,2); y <- List(3,4,5)) yield (x,y)
res1: List[(Int, Int)] = List((1,3), (1,4), (1,5), (2,3), (2,4), (2,5))

Nate

Tony Morris

unread,
Feb 2, 2011, 3:13:13 PM2/2/11
to scala...@googlegroups.com

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

import scalaz._

a <|*|> b

If Haskell helps:

> let (<|*|>) = liftA2 (,) [1, 2] <|*|> [3, 4, 5]
[(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)]

- --
Tony Morris
http://tmorris.net/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk1JutkACgkQmnpgrYe6r63DVwCgzepOy2v9eq1jKwoQvsFW17DL
YpMAoKLsz/cnmkWpMGA6mVqTfT9mKlC2
=Lr5s
-----END PGP SIGNATURE-----

Bill Lear

unread,
Feb 2, 2011, 3:40:36 PM2/2/11
to Nate Nystrom, scala...@googlegroups.com
On Wed, Feb 2, 2011 at 2:09 PM, Nate Nystrom <nate.n...@gmail.com> wrote:
> Hi Bill,
>
> That's not a zip, but rather a cartesian product.  You can create it using a for comprehension:
>
> scala> for (x <- List(1,2); y <- List(3,4,5)) yield (x,y)
> res1: List[(Int, Int)] = List((1,3), (1,4), (1,5), (2,3), (2,4), (2,5))

Wow, what a wealth of options, thanks everyone.

I've applied this to my problem, and have now run into the problem
where I want to apply a function to each member of the resulting list.
I would like to write the function to take distinct parameters,
rather than a list:

def foo(protocol: String, emailAddress: String) {
println("Proto " + protocol + ": " + emailAddress)
}

def main(av: Array[String]) {
val protocols = List("NPV", "XML", "SOAP", "GROD")
val emailAddresses = List("ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com")
val args = protocols.map(x => emailAddresses.map((x, _)))
args.foreach(foo)

But, the compiler does not like this. Is there any way to map things
to a function in this way?

Sorry for the newbie ignorance.


Bill
Bill

alain silovy

unread,
Feb 2, 2011, 4:31:08 PM2/2/11
to scala...@googlegroups.com
Hello,

How should I configure Scala to accept non-Ascii characters?

For instance I get an error message when I place comments in my soucre file containing accented characters (like é, è, à...)

And when reading a text file like here:

import scala.io.Source
 
object gl {
def main(args : Array[String]) {
if(args.length != 1)
println("Usage : scala gl <FileName>")
else
for(ligne <- Source.fromFile(args(0)).getLines)
println(ligne.stripLineEnd)
}
}

does'nt work if the text file contains diacritics...

Thx for the help

Mahmood Ali

unread,
Feb 2, 2011, 4:34:08 PM2/2/11
to Bill Lear, Nate Nystrom, scala...@googlegroups.com
Greetings,

>        val args = protocols.map(x => emailAddresses.map((x, _)))
>        args.foreach(foo)
>
> But, the compiler does not like this.  Is there any way to map things
> to a function in this way?

These should be

val args = protocols.flatMap(x => emailAddresses.map((x, _))
args.foreach(x => foo(x._1, x._2))

If I were you, I would go for

for (x <- protocols; y <- emailAddresses) yield foo(x, y)

- Mahmood

Andreas Scheinert

unread,
Feb 2, 2011, 4:41:17 PM2/2/11
to scala-user
Hi!
Did you know that
(x,y) actually indicates a certain type? Namely : Tuple2
so going from your snippet this works:

def foo[A](tup:Tuple2[A,A]):Unit = println("prot "+tup._1+":"+tup._2)

val args=prots.map(x => mails.map(y => (x,y)))

args.flatten.foreach(foo)
hth Andreas

On Feb 2, 9:40 pm, Bill Lear <bill.l...@gmail.com> wrote:

martin odersky

unread,
Feb 2, 2011, 4:59:03 PM2/2/11
to Mahmood Ali, Bill Lear, Nate Nystrom, scala...@googlegroups.com

So would I. My rule of thumb is, as soon as you have a flatMap in your chain of function applications, consider a for-expression instead. While it means exactly the same thing, it's almost always clearer.

Cheers

 -- Martin

Bill Lear

unread,
Feb 2, 2011, 5:02:34 PM2/2/11
to martin odersky, Mahmood Ali, Nate Nystrom, scala...@googlegroups.com

I agree. Here is my final code example for our Java team:

object It {


def foo(protocol: String, emailAddress: String) {
println("Proto " + protocol + ": " + emailAddress)
}

def main(av: Array[String]) {
val protocols = List("NPV", "XML", "SOAP", "GROD")
val emailAddresses = List("ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com")

for (x <- protocols; y <- emailAddresses) yield foo(x, y)
}
}

Which I think will be relatively easy for our Java developers to grok.


Bill

David Bernard

unread,
Feb 2, 2011, 5:08:42 PM2/2/11
to Bill Lear, martin odersky, Mahmood Ali, Nate Nystrom, scala...@googlegroups.com
Use yield if you return something. for comprehension + yield create a
List (in your case as your first iteration is on a List)
But in your case, you didn't care about return of foo (Unit), then you
don't need to yield.
just
for (x <- protocols; y <- emailAddresses) { foo(x, y) }

/davidB

√iktor Klang

unread,
Feb 2, 2011, 5:34:18 PM2/2/11
to alain silovy, scala...@googlegroups.com
On Wed, Feb 2, 2011 at 10:31 PM, alain silovy <asi...@hotmail.com> wrote:
Hello,

How should I configure Scala to accept non-Ascii characters?

For instance I get an error message when I place comments in my soucre file containing accented characters (like é, è, à...)

And when reading a text file like here:

import scala.io.Source
 
object gl {
def main(args : Array[String]) {
if(args.length != 1)
println("Usage : scala gl <FileName>")
else
for(ligne <- Source.fromFile(args(0)).getLines)

Source.fromFile(args(0), "UTF-8") <--- you need to specify character encoding?
 
        println(ligne.stripLineEnd) 
}
}

does'nt work if the text file contains diacritics...

Thx for the help



--
Viktor Klang,
Code Connoisseur
Work:   Scalable Solutions
Code:   github.com/viktorklang
Follow: twitter.com/viktorklang
Read:   klangism.tumblr.com

Bill Lear

unread,
Feb 2, 2011, 5:36:18 PM2/2/11
to martin odersky, Mahmood Ali, Nate Nystrom, scala...@googlegroups.com

I think I've made a mistake and gotten away from what I originally was
trying for here. I need to separate out the data generation part from
the part that calls the 'foo' method, so my code should really be
something of the sort:

object It {
def foo(protocol: String, emailAddress: String) {
println("Proto " + protocol + ": " + emailAddress)
}

def gen() = {


val protocols = List("NPV", "XML", "SOAP", "GROD")
val emailAddresses = List("ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com", "ema...@pp.com", "ema...@pp.com",
"ema...@pp.com")

for (x <- protocols; y <- emailAddresses) yield (x, y)
}

def main(av: Array[String]) = {
val x = gen()
x.foreach(???)
}
}

Here, I'd like to keep the signature of foo() as it is, easily
comprehensible. Changing it to:

Mahmood Ali

unread,
Feb 2, 2011, 5:43:44 PM2/2/11
to Bill Lear, martin odersky, Nate Nystrom, scala...@googlegroups.com
Greetings,

> I think I've made a mistake and gotten away from what I originally was
> trying for here.  I need to separate out the data generation part from
> the part that calls the 'foo' method, so my code should really be
> something of the sort:
>
> object It {

> [...]


>    def main(av: Array[String]) = {
>        val x = gen()
>        x.foreach(???)
>    }
> }
>
> Here, I'd like to keep the signature of foo() as it is, easily
> comprehensible.

As one of the answers indicated, `(x, y)` type is a Tuple2[X, Y]
instance which can be accessed using the ._1 and ._2 accessors, so you
can do:

val x = gen()
x.foreach(i => foo(i._1, i._2))

You can also still use the for comprehension, which is IMHO a bit more readable:

val x = gen()
for ((prot, email) <- x) { foo(prot, email) }

- Mahmood

Bill Lear

unread,
Feb 2, 2011, 5:52:54 PM2/2/11
to Mahmood Ali, martin odersky, Nate Nystrom, scala...@googlegroups.com
Thanks Mahmood. I've got what I need, so I'll shut up now.

Thanks to everyone else also for helping out.


Bill

Daniel Sobral

unread,
Feb 2, 2011, 6:16:32 PM2/2/11
to Bill Lear, martin odersky, Mahmood Ali, Nate Nystrom, scala...@googlegroups.com
Alternatives:

Function.tupled(foo)
(foo _).tupled
--
Daniel C. Sobral

I travel to the future all the time.

Tony Morris

unread,
Feb 2, 2011, 6:19:12 PM2/2/11
to scala...@googlegroups.com
On 03/02/11 09:16, Daniel Sobral wrote:
> Alternatives:
>
> Function.tupled(foo)
> (foo _).tupled
>
On a slight diversion, we could also add to the standard library:

f => a => b => for(aa <- a; bb <- b) yield f(aa)(bb)

also:

a => b => for(aa <- a; bb <- b) yield (aa, bb)

(which would call the former)

Stefan Wagner

unread,
Feb 2, 2011, 7:35:10 PM2/2/11
to Bill Lear, scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bill Lear schrieb:


> I have two lists:
>
> val a = (1, 2)
> val b = (3, 4, 5)
>
> I would like to create a single list of lists:

I have a solution for an arbitrary number of lists of arbitrary numbers
of elements.

def xproduct (xx: List [List[_]]) : List [List[_]] =
xx match {
case aa :: bb :: Nil =>
aa.map (a => bb.map (b => List (a, b))).flatten
case aa :: bb :: cc =>
xproduct (bb :: cc).map (li => aa.map (a => a :: li)).flatten
case _ => xx
}

which works for a List of two List of Something too.

- --

Tsch���--->...Stefan
- ---------------------------
Don't visit my homepage at:
http://home.arcor-online.net/hirnstrom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)


Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAk1J+D4ACgkQQeATqGpDnRoNEwCglZ8uQsZ5mC2VoEnxqvymePqt
x3cAoIdXX/53wFvRzyJmt6nwDIIsmDLr
=ZRO3
-----END PGP SIGNATURE-----

Vlad Patryshev

unread,
Feb 3, 2011, 2:06:18 AM2/3/11
to Bill Lear, scala...@googlegroups.com
It is not a zip you want, it is a Cartesian product.
So there.

2011/2/2 Bill Lear <bill...@gmail.com>



--
Thanks,
-Vlad

Philippe Lhoste

unread,
Feb 4, 2011, 3:35:44 AM2/4/11
to scala...@googlegroups.com
General advice: start a new message (thread) instead of replying to a random message. Your
message can be unseen by people skipping the thread you hijacked...

On 02/02/2011 22:31, alain silovy wrote:
> How should I configure Scala to accept non-Ascii characters?

I think you should use UTF-8 in your source, it is the default.
For runtime, you can use the -Dfile.encoding setting.

[EDIT] Sending again, shortcutting Gmane, but it seems to have been updated. Am I the only
one to use NNTP to read these lists?

--
Philippe Lhoste
-- (near) Paris -- France
-- http://Phi.Lho.free.fr
-- -- -- -- -- -- -- -- -- -- -- -- -- --

Reply all
Reply to author
Forward
0 new messages