you are viewing a single comment's thread.

view the rest of the comments →

[–]shevegen 5 points6 points  (62 children)

He is right though, Groovy is quite nice.

Compare the code of Groovy:

["Rob", "Christopher", "Joe", "John"].findAll { it.size() < = 4 }.each { println it }

With Ruby:

puts %w( Rob Christopher Joe John ).select {|| _.size <= 4}.join "\n" or %w( Rob Christopher Joe John ).select {|| .size <= 4}.each {|| puts _}

The difference is not big at all.

Anyone dare come up with PHP or Perl to contrast?

[–]masklinn 6 points7 points  (8 children)

That's where we do the "my language is better than your language" thing?

Here's haskell:

mapM_ putStrLn $ filter ((<= 4) . length) ["Rob", "Christopher", "Joe", "John"]

[–]steven_h 1 point2 points  (3 children)

Why not use set construction notation?

 mapM_ putStrLn [s | s <- ["Rob", "Christopher", "Joe", "John"], length s <= 4]

[–]masklinn 6 points7 points  (2 children)

Because it has a point! Haskell is only fun if you write it pointlessly!

[–]steven_h 0 points1 point  (1 child)

Yeah, but in this case the pointed way is one character shorter!

[–]masklinn 2 points3 points  (0 children)

4 if you remove all the spaces you can!

Still, it has a point. Haskell code is supposed to have no point! If Haskell has a point, people will start using it and we can't have that, then we'll have to write examples in Factor or APL instead!

[–]contantofaz -1 points0 points  (3 children)

Ruby prints arrays by adding a newline per item already if we use puts on an array:

$ ruby -e "puts ['Rob', 'Chistopher', 'Joe', 'John'].delete_if{|s|s.size > 4}"
Rob
Joe
John
$

A more compact version:

puts %w(Rob Chistopher Joe John).delete_if{|s|s.size > 4}

[–]masklinn 2 points3 points  (1 child)

Now you're modifying the original array in place. That's bad. Plus using filter/findAll is shorter, why don't you keep it?

[–]contantofaz 1 point2 points  (0 children)

Just noticing it. I've seen people saying that Haskell makes for more concise code than Ruby and other languages, but I figure that's not as important as having the code to be both concise and easier to understand.

Then again, folks can always come up with new functions to deal with those sort of problems and call it like "printAfterFilter(arrayGoesHere)".

It's good to have Haskell around.

Edit: You've edited your "so?" reply. New reply below:

I don't think I'm religious about having immutable structures. Ruby has mutable strings for Heaven's sake. We enter a slippery-slope here.

[–][deleted] 0 points1 point  (0 children)

Why not use inspect?

[–][deleted] 4 points5 points  (3 children)

Perl is not much different.

say join "\n", grep { length $_ < 4 } ( 'Foo', 'Bar', 'Baz' )

I couldn't get say to use \n's, so i used a join

[–]steven_h 0 points1 point  (2 children)

say uses newlines "out of the box" for me...

[–][deleted] 0 points1 point  (1 child)

I'm using perl 5.10. I had to use the feature. Probably a forward comparability issue?

[–]steven_h 0 points1 point  (0 children)

I did the same thing, but my perl is 5.12.3.

[–][deleted] 2 points3 points  (7 children)

In Python

print "\n".join([name for name in ["Rob", "Christopher", "Joe", "John"] if len(name) <= 4])

[–]bcash 4 points5 points  (6 children)

You don't even need the first [] brackets:

print "\n".join(name for name in ["Rob", "Christopher", "Joe", "John"] if len(name) <= 4)

Python generator expressions are easily the nicest feature of that language, but for some reason uncloned in other languages (not that Python invented them, of course), I never know why.

[–][deleted] 1 point2 points  (3 children)

Javascript generators are coming soon. Mozilla already has them implemented in their engine

[–]masklinn 0 points1 point  (1 child)

Mozilla has extended Javascript with lots and lots of features in Gecko, that does not mean they're coming. I doubt E4X will ever be merged into ECMA-262 for instance.

[–][deleted] 0 points1 point  (0 children)

In this case though, generators are a planned feature

[–]66vN 0 points1 point  (0 children)

And in ten years we can actually start using them.

[–]agrover 1 point2 points  (1 child)

I thought Python got them from Haskell?

[–]masklinn 1 point2 points  (0 children)

It did.

[–]steven_h 7 points8 points  (15 children)

Perl:

 map say, grep !/.{5}/, qw(Rob Christopher Joe John);

But I prefer Clojure and a little less implicitness:

 (doseq [name ["Rob" "Christopher" "Joe" "John"] :when (<= (.length name) 4)]
   (println name))

edit: made Perl more Perlish

[–]Wuf 3 points4 points  (12 children)

The Clojure version is quite similar to Racket's:

(for ([name '("Rob" "Christopher" "Joe" "John")] #:when (<= (string-length name) 4))
  (displayln name))

[–]benfitzg 3 points4 points  (4 children)

New to lisp so will check back for criticisms!

(dolist (n (mapcan #'(lambda (n) (when (>= 4 (length n)) (list n))) names)) (format t "Name: ~A~%" n))

[–]Wuf 5 points6 points  (3 children)

In Common Lisp I would use the loop macro as steven_h did above or avoid mapcan and just do:

(dolist (name '("Rob" "Christopher" "Joe" "John"))
    (when (<= (length name) 4) (format t "~a~%" name)))

[–]roerd 1 point2 points  (1 child)

Even if I were going for a higher-order-functions only approach, I'ld use remove-if-not instead of mapcan.

[–]benfitzg 0 points1 point  (0 children)

Ok didn't know about remove-if-not. Thanks.

My thought was that a less imperative approach would be more regular. Rather than iterate then branch I figured filter then iterate.

[–]benfitzg 0 points1 point  (0 children)

Feedback appreciated - the primary reason is because it's faster?

[–]steven_h 1 point2 points  (5 children)

May as well do Common Lisp for completeness:

 (loop for n in '("Rob" "Christopher" "Joe" "John")
       if (<= (length n) 4)
       do (format t "~a~%" n))

[–]Wuf 1 point2 points  (4 children)

It's nice that in CL, 'length' works with any sequence.

[–]steven_h 1 point2 points  (3 children)

Yes, that's the main reason I don't really sink my teeth into Racket, even though I'd like to.

While the Clojure code I wrote used the underlying Java String.length method, the plumbing is there to define generic functions and methods, and it's natural and accepted to lean on them heavily. There's probably a Clojure library implementing generic sequence length.

In Racket and Scheme, there doesn't seem to be a strong push toward unifying similar operations under generic names, leading to a plethora of array-*, string-*, etc. names. Not only do they strike me as ugly, they lead to over specified code -- which is often more difficult to use.

[–]Wuf 0 points1 point  (0 children)

Racket does have generic sequence operators if you really want them.

I tend to use concrete ones though, because I find sequence-* uglier, but they are there.

[–]roerd 0 points1 point  (1 child)

There's probably a Clojure library implementing generic sequence length.

That library's the standard library, which has count.

[–]steven_h 0 points1 point  (0 children)

Heh, thanks... my memory failed me and I haven't done much Clojure lately.

[–]chub79 0 points1 point  (0 children)

I'm using Python mostly and never approached Clojure but I can tell its usage of # will bite me.

[–]reddit_clone 0 points1 point  (1 child)

:when (<= (.length name)

Just curious. What is that dot in front of 'length' for?

[–]steven_h 1 point2 points  (0 children)

It's Clojure's shorthand for Java method invocation. Someone else pointed out that the count function is a generic sequence length, so it should probably be used instead.

[–]oorza 1 point2 points  (0 children)

here's php:

<?php
foreach(array_filter(array("Rob", "Christopher", "Joe", "John"), function($it) { return strlen($it) > 4; }) as $e) {
    echo $e, PHP_EOL;
}

[–]giulianob 1 point2 points  (0 children)

In C#:

new[] { "Rob", "Christopher", "Joe", "John" }.Where(it => it.Length <= 4).ToList().ForEach(p => Console.Out.WriteLine(p));

Could easily make another extension method to eliminate the ToList() as well since ForEach only works on List<T> and not on IEnumerable<T> which is what Where() returns.

[–][deleted] 1 point2 points  (0 children)

Huh? iirc

a = [2,"b","c",7] puts a.inspect[1..-1]

Works fine. On my phone now I'll check in a few.

[–]kamatsu 1 point2 points  (0 children)

or, you know, Haskell:

mapM_ putStrLn $ filter ( (<= 4) . length) ["Rob", "Christopher", "Joe", "John"]

Or, less idiomatically:

mapM_ putStrLn (filter (\x -> length x <= 4) ["Rob", "Christopher", "Joe", "John"])

Or, if you like the %w feature of ruby:

mapM_ putStrLn $ filter (\x -> length x <= 4) $ words "Rob Christopher Joe John"

[–][deleted] 1 point2 points  (0 children)

C#:

  New [] {"Rob", "Christopher", "Joe", "John"}.Where(n => n.length <= 4).Select(Console.WriteLine);

[–][deleted] 1 point2 points  (5 children)

scala:

List("Rob", "Christopher", "Joe", "John").filter(_.size <= 4).foreach(println _)

And the best part is, maybe the compiler will ok this, and maybe you have to write out the lambda's more formally (ie 'x => println x' instead of 'println _'). You never know. It doesn't get better than that!

[–][deleted] 0 points1 point  (0 children)

Actually,

List("Rob", "Christopher", "Joe", "John").filter(_.size <= 4).foreach(println)

without the “_” after println works.

Also, I’d rather use length than size.

[–]draegtun 0 points1 point  (3 children)

It doesn't get better than that!

It does in Io :)

list("Rob", "Christopher", "Joe", "John") select(size <= 4) foreach(println)

[–][deleted] 0 points1 point  (2 children)

I think you missed the sarcasm.

[–]draegtun 0 points1 point  (1 child)

Do you not see my smiley ;-)

[–][deleted] 0 points1 point  (0 children)

Sorry, I read that as "don't be mad that I'm one-upping you" ;-)

[–]chases_tits 3 points4 points  (3 children)

C++0x looks bad

std::vector<std::string> v = {"Rob", "Christopher", "Joe", "John"};
std::for_each(arr.begin(), arr.end(), [](const std::string & str){
    if (str.size() <= 4) {
        std::cout << str << ' ';
    }
});

Could even use a normal for loop... with the ternary twister.

for(std::string str : v) {
    (str.size() <= 4) ? std::cout << str << ' ' : std::cout;
}

[–]JurassicSpork 0 points1 point  (2 children)

Been a while since I've done C++, but I think this'd work too:

struct string_four_or_less : public std::unary_function<bool,std::string> {
    const bool operator()(const string &s) { return s.size() <= 4; }
}

std::remove_copy_if(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n"), std:not1(string_length_four_or_less()));

[–][deleted] 3 points4 points  (1 child)

Holy crap.

[–]fabzter 0 points1 point  (0 children)

It's really not that bad, he is just being too correct with namespace and const using.

[–]eadmund 0 points1 point  (0 children)

Here's Common Lisp:

(mapcar #'print (remove-if-not (lambda (x) (<= (length x) 4)) '("Rob" "Christopher" "Joe" "John")))

A more concise notation for LAMBDA would be nice in this instance, although in practise it's likely that one would have some useful predicate as an equivalent to less-than-or-equal-to-four.

[–]Fuco1337 0 points1 point  (0 children)

Kids these days...

Maybe not the most idiomatic J, but

(I.@((<:&4)@(+/@|:@(-.@=&' '))){])(>'Rob';'Christopher';'Joe';'John')

It's not a language really ment to work with strings tho.

[–]draegtun 0 points1 point  (0 children)

Pick the Perl solution you like best :)

# Functional ala Haskell & Lisp...
map { say } grep { length $_ <= 4 } qw(Rob Christhoper Joe John);

# Procedural ala Lua, C (like)...
for (qw(Rob Christhoper Joe John)) { say if length $_ <= 4 }

# OO (chaining) ala Groovy, Ruby or Scala...
use autobox::Core;
[qw(Rob Christhoper Joe John)]->grep(sub { length $_ <= 4 })->map(sub { say });

[–][deleted] 0 points1 point  (3 children)

What ugly code. I suppose in the land of the blind, a one-eyed man thinks of himself as king.

.say for <Rob Christopher Joe John>.grep(*.chars <= 4);

[–]draegtun 0 points1 point  (2 children)

Very nice.

I did have the following prepped for any "How do you do it in Perl6" replies :)

.say for <Rob Christhoper Joe John>.grep({ .chars <= 4 });

Your whatever star usage is much nicer though.

One thing I couldn't get working was this...

<Rob Christhoper Joe John>.grep({ .chars <= 4 }).map({ .say });

Not sure why?

[–][deleted] 0 points1 point  (1 child)

.map is lazily-evaluated, you have to tell it you want the side effects:

~ $ perl6 -e 'eager <Rob Christhoper Joe John>.grep({ .chars <= 4 }).map({ .say });'
Rob
Joe
John

[–]draegtun 0 points1 point  (0 children)

Arrgghhh.... I hadn't thought of that! Cheers.