Live data from Hacker News

LINQ Ruined My Favorite Interview Question

scottchamberlin.tumblr.com

111–120 of 218 posts

Re: LINQ Ruined My Favorite Interview Question

#111
post #7

/me wonders are candidates allowed to chose their favorite language? man bash | tr '[:upper:] ' '[:lower:]\n' | sed '/^$/d' | sort | uniq -c | sort -rn | head | awk '{ print $2 }' | fmt or do you only hire windows coders?

I should have looked below, I wrote a similar thing above, but you forgot to split multiple words in a line to lines. That's okay, a lot of people above forgot to about case and punctuation even!

Re: LINQ Ruined My Favorite Interview Question

#112
post #8

I hate to be the bearer of bad news, but I think there may be even simpler solutions to this problem: (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #"\+s")))) The above is a Clojure one-liner example that I believe satisfies the original problem. So while LINQ may have simplified from the C-language family solutions he had seen, it's clearly possible to take it one step further with the…

[deleted]

Re: LINQ Ruined My Favorite Interview Question

#113
post #19
post #8

I hate to be the bearer of bad news, but I think there may be even simpler solutions to this problem: (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #"\+s")))) The above is a Clojure one-liner example that I believe satisfies the original problem. So while LINQ may have simplified from the C-language family solutions he had seen, it's clearly possible to take it one step further with the…

Oh, we can use our favorite language in our new job? Here is a Python solution. from collections import Counter Counter(s1.split(' ')).most_common(10)

I find it silly everyone arguing below but when:

s1 = 'a a a a a a a a a a a a a a a a A A A A A A A A A A A A A a. a. a. a. a. a. a. a. a.'

those two lines give:

[('a', 16), ('A', 13), ('a.', 9), ('', 1)

(HN might collapse the double space in s1)

Re: LINQ Ruined My Favorite Interview Question

#114
post #8

I hate to be the bearer of bad news, but I think there may be even simpler solutions to this problem: (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #"\+s")))) The above is a Clojure one-liner example that I believe satisfies the original problem. So while LINQ may have simplified from the C-language family solutions he had seen, it's clearly possible to take it one step further with the…

how does FREQUENCIES know how to compare strings? In Common Lisp you'd usually supply a TEST keyword parameter (#'STRING= or #'EQUAL in this case). Does Clojure use Java's type system to infer?

Clojure uses a unified compare test, sometimes called equiv. I think its passed on this paper, http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.23.9...

Re: LINQ Ruined My Favorite Interview Question

#115
post #25
post #21

Earlier quoted context omitted.

Well, sure, once you're allowed to use external libraries anything is a one line solution. In JS: doStuff = require("doStuff"); var result = doStuff(theString); isn't JS so efficient ?!?

It looks like collections is part of the standard library: http://docs.python.org/2/library/collections.html . I think this disqualifies your JS solution, as long as doStuff isn't some fancy nodejs core module I missed.

"Sorry, we're stuck with Python 2.3.7 and collections isn't part of the standard library."

Re: LINQ Ruined My Favorite Interview Question

#116

Earlier quoted context omitted.

but seriously, if you're writing c# and not using LINQ all the time You don't sound arrogant, but rather sound naive. I agree that someone who recruits surely should have known about and have experienced LINQ significantly by now, but the notion that you should be using it "all the time" is absolute nonsense. I avoid LINQ. I encourage others to avoid LINQ. It is almost always a sign of bad code. LINQ is syntactical s…

(Note: When I say LINQ I am referring to the functional style it encourages, not the query syntax. The query syntax is nice, but it's just a trivial syntactic transformation.) Correct me if I'm wrong, but the world is moving towards functional programming (i.e. LINQ) not away from it. Personally, I find LINQ far, far easier to read, write, and analyze. (On the other hand, I understand the deferred semantics and watch…

I'm definitely in agreement with the last point. However, I originally said that good C# code contains a lot of LINQ, not that C# code with a lot of LINQ is necessarily good. Deferred execution is something that confuses people, but frankly, it's a concept they need to learn. It's been in the language since yield return got added in 2.0.

LINQ's deferred execution was the right choice for performance, but it's the hardest one. You've got to know when to call .ToList(). I'm not denying that I've seen people evaluate the same expensive list 100 times, use a join when precomputing a Dictionary would have been much faster, close a connection before the result is actually evaluated. But I've never seen C++ programmers say you can make mistakes with pointers, so don't them.

Clojure's lazy sequences are guaraanteed to evaluate once, but that comes at the expense of storage. In particular, a query like the one in the original blog post will evaluate multiple intermediate lists that then need to be thrown away. And indeed, they've introduced reducers to address this, which behaves more like LINQ.

Re: LINQ Ruined My Favorite Interview Question

#117
post #44
post #8

I hate to be the bearer of bad news, but I think there may be even simpler solutions to this problem: (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #"\+s")))) The above is a Clojure one-liner example that I believe satisfies the original problem. So while LINQ may have simplified from the C-language family solutions he had seen, it's clearly possible to take it one step further with the…

While we're golfing, (comp first rest) is equivalent to the stdlib function called second , or, perhaps more idiomatic for map entries, val . We can also flatten deeply nested chains of computation using the -> and ->> macros, like so: (->> (string/split ... #"\s+") frequencies (sort-by val) reverse (take 10))

Think you also need a (map key) there to be equivalent to the C# code. At which point it's starting to look very similar to well written C# code solving the same problem.

Much as I love Clojure, it's worth pointing out that Clojure's lazy sequences (include intermediate sequences) get cached, while LINQ evaluates more like Clojure's reducers. (You can even get it to do so in parallel.)

Re: LINQ Ruined My Favorite Interview Question

#119
post #8

I hate to be the bearer of bad news, but I think there may be even simpler solutions to this problem: (take 10 (reverse (sort-by (comp first rest) (frequencies (string/split ... #"\+s")))) The above is a Clojure one-liner example that I believe satisfies the original problem. So while LINQ may have simplified from the C-language family solutions he had seen, it's clearly possible to take it one step further with the…

  s.Split(' ').GroupBy(x => x).OrderByDescending(x => x.Count()).Select(x => x.Key).Take(10).ToList();
I'd say 13 characters isn't really a huge differentiator. They're both using exactly the same algorithm, almost exactly the same built-in library functions, and have exactly the same flexibility for programmers to add their own (C# is using extension methods which lets you add methods that look like they belong to the class, but are actually static methods defined elsewhere).

There's a lot of benefits to Clojure over C#, but the ability to chain functional list operators really isn't one of them.

Re: LINQ Ruined My Favorite Interview Question

#120
post #117
post #44

Earlier quoted context omitted.

While we're golfing, (comp first rest) is equivalent to the stdlib function called second , or, perhaps more idiomatic for map entries, val . We can also flatten deeply nested chains of computation using the -> and ->> macros, like so: (->> (string/split ... #"\s+") frequencies (sort-by val) reverse (take 10))

Think you also need a (map key) there to be equivalent to the C# code. At which point it's starting to look very similar to well written C# code solving the same problem. Much as I love Clojure, it's worth pointing out that Clojure's lazy sequences (include intermediate sequences) get cached, while LINQ evaluates more like Clojure's reducers. (You can even get it to do so in parallel.)

You're right; it does need a (map key) line to be equivalent. I was thinking of http://www.leancrew.com/all-this/2011/12/more-shell-less-egg..., which wants the counts too. :)

On a side note, I'd like to point out a key difference between this Clojure example and corresponding variants in C#, Python, &c: the Clojure variant has no variables. This isn't just a matter of concision: coming up with descriptive names is hard, and usually means duplicated information, either in the name or the type declaration. Often, those names are re-used over and over again with subtly different meanings, for each stage in a pipeline--forcing the reader to reason carefully about the declaring scope at each use.

Consider, for example:

  Swimmer swimmer = new Swimmer("foo");
  swimmer.setStyle("butterfly");
  swimmer.swim();
  return swimmer;

  (doto (Swimmer. foo)
        (.setStyle "butterfly")
        .swim)
Same operation--but with (doto), four uses of a variable and one type declaration have been cleared away. Consider the original post:

  var words = s.Split(' ');
  var wordCounts = words.GroupBy(x => x).Select(x => new { Name = x.Key, Count = x.Count() }).OrderByDescending(x => x.Count);  
  var countedWords = wordCounts.Select(x => x.Name).Take(10).ToList();
  return ExtractTopTen(countedWords);
Six uses of three formal variables, including the bewilderingly confusable countedWords and wordCounts, plus nine uses of the delightfully generic "x". Even in the more compact C# example from this thread, consider:

  var top = (from w in text.Split(' ') 
             group w by w into g 
             orderby g.Count() descending 
             select g.Key).Take(10);
This variant refers to the temporary variables w (for "words") and g (for "groups"?) six times. Both authors felt the need to reduce the repetition of variables, but the best they could do was to choose single-character names.

This is the real power of ->, .., ->>, doto, and friends: eliminating names for things. By thinking about the composition of transformations, instead of the intermediate results, you can make an algorithm easier to understand and change.

Post reply on HN