Live data from Hacker News

LINQ Ruined My Favorite Interview Question

scottchamberlin.tumblr.com

171–180 of 218 posts

Re: LINQ Ruined My Favorite Interview Question

#171

(his name is Jon Skeet) (sorry)

     string s,f;
     map M;
     set > S;
     while(cin >> s) {
             M[s]++;
             int x=M[s];
             if(x>1) S.erase(make_pair(x-1,s));
             S.insert(make_pair(x,s));
     }
     set >::reverse_iterator it=S.rbegin();
     int topK=10;
     while(topK-- && (it!=S.rend())) {
             cout secondfirst

Re: LINQ Ruined My Favorite Interview Question

#172
post #4

LINQ tends to get thought of as "database syntax sugar", but it's way more than that. It's C#'s version of the lazy collection operations you find in most functional languages, just given friendlier sqlish names. (IE, "Select" instead of "map" and "Where" instead of "filter") I almost feel a bit gross when I have to write a "foreach" loop at this point, because there's almost always an equivalent way to do it in LINQ…

The most annoying thing about LINQ is that they use the SQL language. So unless you use C# and LINQ all of the time it's hard to figure out what functions translate to the ones used by every functional language in the world. I wish they would at least alias map, reduce, some, etc.

Well, SQL is by far the most used functional language in the world.

Re: LINQ Ruined My Favorite Interview Question

#173
post #78
post #68

Earlier quoted context omitted.

I'm a newbie, but the question seemed approachable so I went for it. This is what I came up with. (Python, btw.) def top_ten(s): words = s.split(' ') word_list = set(words) return sorted(word_list, key=lambda x: words.count(x))[:10] The question didn't ask for word counts, so I didn't see the need for a dictionary. I'd appreciate any advice on my solution. I'd be thrilled if I'm not too far off from being capable of…

The need for the dictionary shows up when your text gets significantly large. Each call to `words.count` is going to re-examine each word of the text to count 'em up, so, if n is the number of words in the text, and m is the number of distinct words in the text, then this solution is at least O(mn + n log(n)) whereas the dictionary-based solution is O(n log(n)). That is, we're re-reading the word list over and over,…

Isn't the difference between O(mn + nlog(n)) vs O(nlog(n)) running time going to get less significant as the value of n gets larger?

I thought the whole point of Big O / asymptotic analysis is that you can ignore lower-order terms and constant factors because they are insignificant for any appreciably large input size. And also because the lower order terms and constant factors vary too much depending on the programming language, the compiler or VM, the hardware, etc.

Re: LINQ Ruined My Favorite Interview Question

#174
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)

meh, just use sum instead of counter

sorted([(i,sum([i==j for j in s.split()])) for i in list(set(s.split()))],key=lambda x:x[1],reverse=True)[:10]

Re: LINQ Ruined My Favorite Interview Question

#175
post #86

Earlier quoted context omitted.

The OP blog-post doesn't really represent it succinctly in C#. This is the most succinct way I could think of: var top = (from w in text.Split(' ') group w by w into g orderby g.Count() descending select g.Key).Take(10);

Though that will result in a lot more calls to Count(). A let would fix that.

I really really really should learn more Linq. Where would I use let, and why?

Re: LINQ Ruined My Favorite Interview Question

#176
post #154
post #68

Earlier quoted context omitted.

I'm a newbie, but the question seemed approachable so I went for it. This is what I came up with. (Python, btw.) def top_ten(s): words = s.split(' ') word_list = set(words) return sorted(word_list, key=lambda x: words.count(x))[:10] The question didn't ask for word counts, so I didn't see the need for a dictionary. I'd appreciate any advice on my solution. I'd be thrilled if I'm not too far off from being capable of…

Ooh, this is fun! In Ruby, without imports/requires: def toptenwords(str) words = str.split words.sort_by{|word| words.count(word)}.uniq.reverse.take(10) end or as a one-liner, without any variable declarations in the function scope: def toptenwords(str) str.split.sort_by{|word| str.split.count(word)}.uniq.reverse.take(10) end

I think this version and spenuke's version are impractically slow, but yours is actually O(N²). If you give it an 824 000 word input, it will do 0.6 quadrillion word comparisons, which you will probably not be willing to wait for. A more practical solution:

    counts = Hash.new { 0 }
    IO.read('bible-pg10.txt').split.each { |w| counts[w] += 1; }
    counts.keys.sort_by { |w| -counts[w] }.take 10
This is still O(N lg N) instead of O(N lg 10) like the Python version, but it's good enough this time; it still gave me ["the", "and", "of", "to", "And", "that", "in", "shall", "he", "unto"] reasonably quickly.

I'd be interested to see if there's a way to do this in a single expression in Ruby.

Re: LINQ Ruined My Favorite Interview Question

#177
post #105
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…

For a sys-admin job: tr 'a-z' 'A-Z' | sed 's/[^A-Z][^A-Z]*/\ /g' | grep -v '^$' | sort | uniq -c | sort -nrk1 | head -10 edit: I don't know enough about HN,there should be a newline after the backslash in the sed command.

You can use tr instead of sed and grep, too. Also -k1 and -n 10 are default for sort and head:

    $ 
I have a `bins` script that is just `sort | uniq -c | sort -nr`, so that reduces to `tr -cs a-zA-Z '\n' | bins | head`.

Unix for Poets, man. It's the shit.

Re: LINQ Ruined My Favorite Interview Question

#178
post #137
post #116

Earlier quoted context omitted.

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 har…

In particular, a query like the one in the original blog post will evaluate multiple intermediate lists that then need to be thrown away. Why not fuse the operations, if the values are immutable?

Well, there's two ways to do that in Clojure: write your own list processing (usually regarded as bad style) or use reducers. Both are appropriate in specific instances, but the fact remains that the lazy seq code above is the idiomatic way of doing it in Clojure. So the _default_ way of doing it is slower than LINQ's default way of doing things.

It wouldn't be hard to make LINQ behave like Clojure, either.

Re: LINQ Ruined My Favorite Interview Question

#179
post #82
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…

Since we're already on the JVM, here's my solution for Scala: def top10(s: String) = s.split(' ').groupBy(identity).mapValues(_.size).toList.sortBy(-_._2).take(10).map(_._1)

That's almost identical to what I came up with, but yours is better...I didn't know about the mapValues function.

def mostCommon(str: String, num: Int) = { str.split(" ").groupBy { s => s} .map { case (k,v) => k -> v.length }.toList .sortBy { _._2 }.reverse.take(num).map { _._1 } }

Re: LINQ Ruined My Favorite Interview Question

#180
post #120
post #117

Earlier quoted context omitted.

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…

> Six uses of three formal variables, including the bewilderingly confusable countedWords and wordCounts, plus nine uses of the delightfully generic "x".

I totally agree with you on this.

>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.

You lost me somewhere along the way....are you saying the "from w in text"... snippet is bad, and something more along the lines of "This is the real power of ->, .., ->>" is more appropriate?

I ask because that code seems extremely readable to me. Personally, I don't give a shit if it's 30% more verbose or runs 50% slower, for 99% of code (written in the world), optimum performance doesn't matter. Maintainability does matter though. All of this software being written today has to be either maintained by someone, or replaced by something else. And the top ~2% of programmers like you sure as hell aren't going to be taking maintenance jobs any time soon.

I'm curious what the thoughts of a technically smart person such as yourself are on the subject of what companies will be left with 5 to 10 years down the road when consultants have come through and implemented using the currently most optimum platform/language/algorithms?

And I honestly don't mean for this question to be disrespectful. I'm just coming from a situation where I'm a former developer but on a project where I'm not coding, and I ask for features and the developers say they can't do it, or it will be a performance problem. And I know these guys are far more like you than me intelligence/education wise, but the things I ask for I've done tons of times in the past with 10 to 1000 times the data size, without a problem, on far older hardware.

I'm just curious what kind of a support problem you ultra smart people are leaving behind, or if you ever think about the idea that almost no on else is as smart as you?

Post reply on HN