Faster List Intersection Using Skip Pointers

IntersectionAs I mentioned in my previous post about array intersection, all the work we did was to enable us to experiment with skip pointers. You may remember me saying that list intersection was the most important operation when it comes to search engines. This is because in web search, most queries are implicitly intersections. Consider, when your query contains multiple words (e.g. “car repairs”, “britney spears songs” etc.) the search engine will translate this into – (car AND repairs”, “britney AND spears AND songs), which means it will be intersecting 2 or more postings lists in order to return a result. Because intersection is so crucial, search engines try to speed it up in any way possible. One such way is to use skip pointers.

What Are Skip Pointers

As you recall from my previous post if the sizes of our two posting lists are x and y, the intersection takes x+y operations. Skip pointers allow us to potentially complete the intersection in less than x+y operations. Here is how. At indexing time, we augment our posting lists of document identifiers with a set of “short cut” pointers that reference values further along in the list e.g.:

Skip Pointers

This way, if the situation allows, we can avoid processing parts of the list by following this pointer whenever this will have no impact on our intersection operation.

Here is an example, let us say we want to merge two posting lists for the words “car” and “repairs” which have been augmented with skip pointers like so:

Skip Pointers

We would start using our normal intersection algorithm. We continue advancing through both lists until we have matched 12 and advanced to the next item in each list. At this point the “car” list is sitting on 48 and the “repairs” list is on 13, but 13 has a skip pointer. We check the value our skip pointer is pointing at (i.e. 29) and if this value is less than the current value of the “car” list (which it is), we follow our skip pointer and jump to this value in the list. This allows us to skip 3 items in the “repairs” list since we know they weren’t going to match anyway. Using this technique we can complete an intersection operation faster than we would have been able to otherwise.

We can immediately see a problem. If we augment our data with skip pointers there is now extra overhead for storing these as well as checking for their existence, as well as the overhead involved in actual skip pointer comparisons. This can negate any advantage we gain for our intersections. In practice you don’t want to have too many skips for this very reason, but you also don’t want to have too few as this defeats the purpose of having skips in the first place.

One simple heuristic which has been shown to work well, is to have sqrt(n) evenly spaced skip pointers for a posting list of size n (this is decent but not the best as it doesn’t take into account the distribution of your query terms). What we are going to try and do is test empirically whether or not skip pointers will allow us to improve the speed of an intersection operation.

The Test Data

The first thing to do is to generate some dummy posting lists. We use the following function:

ruby def create_wrapped_mock_postings_list(min_postings, max_postings, corpus_size) postings_list = [] num_postings = min_postings + rand(max_postings) num_postings.times do wrapped_id = OpenStruct.new wrapped_id.value = rand(corpus_size) + 1 postings_list << wrapped_id end postings_list.sort{|x,y| x.value <=> y.value}.block_uniq{|item| item.value} end

This generates a list of between _minpostings and _maxpostings document ids each of which is a number between 1 and _corpussize. We also need to wrap each of our raw numbers in a container since we know we will be augmenting them with skip pointers.

Putting in the skips turned out to be reasonably complex, making sure they were evenly spaced according to our heuristic (sqrt(n)) as well as making sure everything was correctly handled when we got to the end of the list. The augment_wrapped_list_with_skips does a reasonable job, using two other helper functions. There is nothing really revolutionary about these, they were just extremely fiddly to write.

```ruby def calculate_skip_index_for(skip_number, values_to_skip) skip_index = skip_number * values_to_skip skip_index = skip_index - 1 if skip_index > 0 skip_index end

def build_skip_index_hash_for(list) skip_indexes = {} number_of_skips = Math.sqrt(list.size).to_i number_to_skip = (list.size/number_of_skips).to_i (0..number_of_skips - 1).each do |skip_number| skip_index = calculate_skip_index_for(skip_number, number_to_skip) skip_indexes[skip_index] = calculate_skip_index_for(skip_number + 1, number_to_skip) end skip_indexes end

def augment_wrapped_list_with_skips(list) skip_indexes = build_skip_index_hash_for list list.each_with_index do |list_item, list_index| if skip_indexes.key? list_index list_item.skip_index = skip_indexes[list_index] list_item.skip_value = list[skip_indexes[list_index]].value end end end```

The New Intersection Function

Now that we’re able to augment our lists with skips, all we need as an intersection function that will take advantage of this:

ruby def rubyish_intersect_for_wrapped_with_skips(list1, list2) list3 = [] skips = 0 list1.each_with_skips do |item1, index1| next_index1 = nil list2.each_continued do |item2, index2| if item1.value == item2.value list3 << item2 index2 + 1 elsif item1.value < item2.value while !item1.skip_index.nil? && item1.skip_value <= item2.value next_index1 = item1.skip_index item1 = list1[next_index1] skips += 1 end index2 else next_index2 = nil while !item2.skip_index.nil? && item2.skip_value <= item1.value next_index2 = item2.skip_index item2 = list2[next_index2] next_index1 = index1 skips += 1 end next_index2 end end next_index1 end list3 end

As you can see it is quite a bit more complex than the previous intersection functions we have written. This does nothing more than what I described above:

  • looks for a skip pointer
  • if found, checks the value it is pointing at
  • figures out if we’re able to follow the skip by comparing the current value of the other list with the value the skip is pointing at
  • follows the skip pointer if possible

It could certainly use a helper function or two, but I believe keeping it all in one place makes the algorithm a bit clearer. One thing to note is the fact that the outer each iterator is no longer just a standard one, we’ve had to open up our Array class and add the following:

ruby class Array def each_with_skips current_index = 0 while current_index < self.size next_index = yield(self[current_index], current_index) if next_index current_index = next_index else current_index += 1 end end end end

This essentially allows us to return a value from the block, which will be used as the index to continue the iteration from on the next pass, allowing us to “skip” a number of values when we’re able to follow the skip pointers of the outer iterator. The inner iterator still uses the “_eachcontinued” function that we wrote in the last post as it already had the ability to skip values when necessary. If you can re-write this intersection function to be tighter and more “ruby-ish”, do share it, I’d be intersected to see what other people can come up with.

The Experiment

We’re now ready to run our experiment to see if skip pointers can actually make a difference. All we need is a method to time the execution of our intersection functions. Fortunately I have written about timing Ruby code before (how lucky is that :)), so we’ll just take the timing method from there:

ruby def time_method(method=nil, *args) beginning_time = Time.now if block_given? yield else self.send(method, args) end end_time = Time.now puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds" end

We want to compare three things:

  • intersecting two lists of raw integers (not augmented by skip pointers and not wrapped by another object)
  • intersecting two lists of “wrapped” integers (wrapped by another object to possibly contain more data) without using skip pointers
  • intersecting two lists of “wrapped” integers (wrapped by another object to possibly contain more data, such as the skips) using skip pointers

Here is the code:

```ruby def create_raw_mock_postings_list(min_postings, max_postings, corpus_size) postings_list = [] num_postings = min_postings + rand(max_postings) num_postings.times do postings_list << rand(corpus_size) + 1 end postings_list.sort.uniq end

def wrap_raw_list(list) wrapped_list = [] list.each do |item| wrapped_item = OpenStruct.new wrapped_item.value = item wrapped_list << wrapped_item end wrapped_list.sort{|x,y| x.value <=> y.value}.block_uniq{|item| item.value} end

CORPUS_SIZE = 100000000

raw_list1 = create_raw_mock_postings_list(100, 200, CORPUS_SIZE) raw_list2 = create_raw_mock_postings_list(30000, 50000, CORPUS_SIZE)

wrapped_list1 = wrap_raw_list(raw_list1) wrapped_list2 = wrap_raw_list(raw_list2)

wrapped_list1_with_skips = augment_wrapped_list_with_skips(wrapped_list1) wrapped_list2_with_skips = augment_wrapped_list_with_skips(wrapped_list2)

puts “” puts “RAW” puts “———————————————————” time_method(:rubyish_intersect_for_raw, raw_list1, raw_list2) puts “” puts “WRAPPED” puts “———————————————————” time_method(:rubyish_intersect_for_wrapped, wrapped_list1, wrapped_list2) puts “” puts “WRAPPED WITH SKIPS” puts “———————————————————” wrapped_list1_with_skips.reset_current_index wrapped_list2_with_skips.reset_current_index time_method(:rubyish_intersect_for_wrapped_with_skips, wrapped_list1_with_skips, wrapped_list2_with_skips)```

Running this, we get results similar to the following:

RAW
---------------------------------------------------------
Time elapsed 59.634 milliseconds

WRAPPED
---------------------------------------------------------
Time elapsed 265.142 milliseconds

WRAPPED WITH SKIPS
---------------------------------------------------------
Time elapsed 245.459 milliseconds

I won’t bore you by running this dozens of times here, suffice to say I did run this lots and lots of times while tweaking the parameters :) (i.e. the sizes of the lists, the corpus size). Here is what I found.

No matter what you do, intersecting a “raw” (not wrapped in a decorator and no skip pointers) list is always significantly faster. This is to be expected, but ultimately means nothing since it is not possible to augment these raw values with skip pointers anyway. Regardless in a real search engine index, document ids in posting lists will often need to contain extra data in addition to skip pointers (e.g. positional information etc.) and so will almost never be raw numbers. What we’re really interested in is comparing “wrapped” lists with and without skips. As you can see from the output above, skip pointers made the list intersection slightly faster, but this is not always the case. Here are some interesting facts that I have found:

  • when both lists are sufficiently small, we never skip but the time difference is negligible due to the size of the lists
  • for larger lists of similar size (i.e. both lists around 30000 values) skip pointers are followed rarely and are therefore actually detrimental to the performance of the intersection function (due to the overhead of checking the skip values but being unable to follow), with the times being 10% to 40% slower for lists with skips
  • when posting list sizes are orders of magnitude different (i.e. list of size 200 vs list of size 20000 like the code above), skip pointers begin to come into their own since the larger list is able to skip a lot more often, the improvement is around 10% to 40% (10 is more likely than 40)

As you can see, skip pointers certainly can improve the speed of an intersection function, but only in certain situations. Of course there are a couple of things to be aware of. Firstly, random generation of posting lists data may not be representative of the distribution of the document ids, in a posting list, in a real search engine index. When randomly generated, document ids end up evenly distributed across the size of the corpus, in real life, this is likely not to be the case, which may allow us to skip a lot more often, improving performance. Secondly, we augmented our data with skip pointers in a somewhat naive fashion (sqrt(n)). If we can come up with another heuristic that will fit our data better (through data analysis), we may be able to improve performance even more. Well, there we go, some interesting code, a new concept and a modified intersection algorithm, don’t forget to subscribe to my feed if you enjoyed it. As always, if you have something to add or have a question, I’d love to hear from you. 

The Best Funny And Educational Geek Songs

I’ve been writing a lot of opinion and coding posts lately a few of which have generated some controversy. So, I thought that before I go on to write more serious stuff that generates even more controversy (this seems to be inevitable :)), I would have a bit of a break and have some fun. To that effect I have compiled a list of my favorite educational and funny songs for geeks. Rather than putting together a list of more “mainstream” geek anthems (if geek songs can ever be considered mainstream) which has been done before, I thought I would focus on the lighter and more educational side of geek music, although some songs are just such classics that I couldn’t bear not to have them on this list (I am sure you will know them when you see them). Anyways, without further verbiage, here is the list, hope you like it and spot some old favorites.

Note: I’ll post links to the lyrics of every song, but you know how those lyrics websites are, so don’t forget to turn on your adblockers, or just listen to the songs instead :)**_.

_**

10. Pinky And The Brain – “Parts Of The Brain”

If you want to know what parts the brain is made out of, this is a fun way to learn. The lyrics can be found here.

Best Lines

cerebellum left
cerebellum right
synapse-hypothalamus
triaden-dendrite

9. The Firm – “Star Trekkin’”

If you’re into Star Trek – The Original there is something about this song that just gets you. It’s not particularly educational, but sure is funny (only if you know your Star Trek :)). The lyrics – such as they are – can be found here.

Best Lines

Ah! We come in peace, shoot to kill, shoot to kill, shoot to kill;

1
2
3
4
5
6
7
<p>
  and
</p>

<p>
  <em>Ye cannae change the laws of physics, laws of physics, laws of physics;</em>
</p>

8. Histeria! – “The Invasion Song”

Histeria! was an awesome cartoon from the late 90s when the edutainment kick was at it’s height. These guys took it to a whole new level though. The show has never been released on DVD – as far as I know – so videos are ultra-hard to find. This song manages to fit half the invasions from recorded history into a couple of minutes – fun and you’ll learn stuff. The lyrics are here, but do check out the lyrics to the rest of their songs, they even have one about Charles Babbage (I would have put that one here since it is arguably more geeky, but I can’t find it anywhere :)).

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<p>
  <strong>Best Lines</strong>
</p>

<blockquote>
  <p>
    <em>Can't we all just get along,<br /> Why do we have to fight?<br /> Why not just accept you're wrong,<br /> Admit that I was right?</em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>Let's all be one big family like<br /> Those in-laws that you have made<br /> And for two weeks every summer, man,<br /> You know&#8230;they're gonna invade!</em>
  </p>
</blockquote>

<h2>
  7. Animaniacs &#8211; "Nations Of The World"
</h2>

<p style="text-align: center;">
</p>

<p>
  Like the "<em>Brain Song</em>" and the "<em>Invasion Song</em>" (above) and the "<em>Element Song</em>" (below), this is a list song. It is just brilliant all round, I wonder if it managed to fit all of the countries in &#8211; I believe they did &#8211; can anyone confirm? Here are the <a href="http://www.stlyrics.com/songs/a/animaniacs8676/nationsoftheworld491365.html" target="_blank">lyrics</a>.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>Burundi, Lesotho, and Malawi, Togo<br /> The Spanish Sahara is gone,<br /> Niger, Nigeria, Chad, and Liberia<br /> Egypt, Benin, and Gabon.<br /> </em>
  </p>
</blockquote>

<h2>
  6. Monty Python &#8211; "The Galaxy Song"
</h2>

<p style="text-align: center;">
</p>

<p>
  Monty Python is just a<span id="main" style="visibility: visible;"><span id="topstuff" style="visibility: visible;"><a class="spell" href="http://www.google.com.au/search?hl=en&ei=GImjS7OtDtegkQXgw4XpCA&sa=X&oi=spell&resnum=0&ct=result&cd=1&ved=0CAUQBSgA&q=smorgasbord&spell=1"><b><i> </i></b></a>smorgasbord of geek music, but I just love this one, it is tiny and simple and full of nice factoids besides which it is clever and funny. All geeks love it. The lyrics can be found <a href="http://www.lyricsdepot.com/monty-python/galaxy-song.html" target="_blank">here</a>.<br /> </span></span>
</p>

<p>
  <strong><span style="visibility: visible;"><span style="visibility: visible;">Best Lines</span></span><br /> </strong>
</p>

<blockquote>
  <p>
    <em>Our galaxy itself contains a hundred billion stars.<br /> It's a hundred thousand light years side to side.<br /> It bulges in the middle, sixteen thousand light years thick,<br /> But out by us, it's just three thousand light years wide.<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>And pray that there's intelligent life somewhere up in space,<br /> 'Cause there's bugger all down here on Earth. <br /> </em>
  </p>
</blockquote>

<h2>
  5. "Weird Al" Yankovic &#8211; "It's All About The Pentiums"
</h2>

<p style="text-align: center;">
</p>

<p>
  Weird Al is another constant source of geek music, but I have to say that the two songs on this list are his best work as far this niche genre is concerned. You gotta read the <a href="http://www.azlyrics.com/lyrics/weirdalyankovic/itsallaboutthepentiums.html" target="_blank">lyrics</a> for this one, they are awesome.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>Yeah, payin' the bills with my mad programming skills<br /> Defraggin' my hard drive for thrills<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>You think your Commodore 64 is really neato<br /> What kinda chip you got in there, a Dorito?<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>In a 32-bit world, you're a 2-bit user<br /> You've got your own newsgroup, "alt.total-loser"<br /> </em>
  </p>

  <p>
    and way more
  </p>
</blockquote>

<h2>
  4. Tom Lehrer&rsquo;s &#8211; "Element Song"
</h2>

<p style="text-align: center;">
</p>

<p>
  This old-school song just lists the elements, but does it brilliantly, of course it is a little out of date these days, (<em>i.e. some new ones have been discovered</em> :)). If you want to learn the elements you could certainly find many worse ways. Here are the lyrics.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>These are the only ones of which the news has come to Havard,<br /> And there may be many others, but they haven't been discavard.<br /> </em>
  </p>
</blockquote>

<h2>
  3. Jonathon Coulton's &#8211; "Code Monkey"
</h2>

<p style="text-align: center;">
</p>

<p>
  This one has already become a classic so I couldn't really leave it out despite the fact that it is neither educational or particularly funny. It is however rather accurate in so many clever ways, have a listen and then a <a href="http://www.leoslyrics.com/listlyrics.php?hid=%2Fm03GGhfPAk%3D" target="_blank">read</a>.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>Code Monkey think maybe manager want to write goddamn login page himself <br /> Code Monkey not say it out loud <br /> Code Monkey not crazy just proud <br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>Much rather wake up eat a coffee cake<br /> Take bath, take nap<br /> This job fulfilling in creative way<br /> such a load of crap <br /> </em>
  </p>
</blockquote>

<h2>
  2.&nbsp; Barenaked Ladies &#8211; "The History of Everything"
</h2>

<p style="text-align: center;">
</p>

<p>
  You will recognize this one as the theme song to our favorite geek sitcom &#8211; "<a href="http://en.wikipedia.org/wiki/The_Big_Bang_Theory" target="_blank">The Big Bang Theory</a>", which gives it some special street-cred all on it's own, but it is actually a really great and clever song overall &#8211; despite being rather short. Try describing the history of the universe in under 2 minutes. Here are the <a href="http://www.justsomelyrics.com/1581273/Barenaked-Ladies-History-of-Everything-Lyrics" target="_blank">words</a>.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>The dinosaurs all met their fate<br /> They tried to leap but they were late<br /> And they all died (they froze their asses off)<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>Australopithecus would really have been sick of us <br /> Debating how we're here, they're catching deer (we're catching viruses)<br /> </em>
  </p>
</blockquote>

<h2>
  1. "Weird Al" Yankovic &#8211; "White and Nerdy"
</h2>

<p style="text-align: center;">
</p>

<p>
  If you haven't heard this one, you've been living on mars for the last few years, with your eyes closed and your fingers stuck in your ears :). It is a totally brilliant parody of the song "<em>Ridin'</em>" by Chamillionaire, but you don't need me to describe it for you, here is <a href="http://en.wikipedia.org/wiki/White_&_Nerdy" target="_blank">Wikipedia</a>. Lyrics are <a href="http://www.azlyrics.com/lyrics/weirdalyankovic/whitenerdy.html" target="_blank">here</a>, you absolutely have to look at these, like I said &#8211; genius.
</p>

<p>
  <strong>Best Lines<br /> </strong>
</p>

<blockquote>
  <p>
    <em>My rims never spin to the contrary<br /> You'll find they're quite stationary<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>I memorized Holy Grail really well <br /> I can recite it right now and have you ROTFLOL<br /> </em>
  </p>

  <p>
    and
  </p>

  <p>
    <em>Only question I ever thought was hard<br /> Was do I like Kirk or do I like Picard?<br /> </em>
  </p>
</blockquote>

<p>
  That makes it a top ten, but of course there is<strong> always something that gets left out of the top 10</strong>, so I'll just put a few more awesome songs right here down the bottom &#8211; I won't tell the list police if you don't :).
</p>

<h2>
  11. Animaniacs &#8211; "Yakko&rsquo;s Universe"
</h2>

<p style="text-align: center;">
</p>

<p>
  Just another song about the universe &#8211; fun.
</p>

<h2>
  12. Monty Python &#8211; "Philospher's Song"
</h2>

<p style="text-align: center;">
</p>

<p>
  Learn some philosopher names to impress your friends at parties :).
</p>

<h2>
  13. Histeria! &#8211; "The Tale of the Tudors"
</h2>

<p style="text-align: center;">
  <p>
    The whole history of the Tudors in about 3.5 minutes. The song is actually slightly inconsistent with itself :), can you spot where?
  </p>

  <p>
    There you have it, funny, educational and a nice break from hardcore $1 for more craziness (<em>also seems to be inevitable &#8211; the craziness :)</em>).
  </p>

An Interview Question That Prints Out Its Own Source Code (In Ruby)

A program that prints out its own source code (without reading in and outputting it’s source file) is known as a quine. I’ve known about these things for years, but never really bothered trying to work it out. It requires thinking in a circular fashion which makes your head hurt :). However, a little while ago a realized that this would actually make a great programming interview question, so I thought I had better give this a crack, using Ruby – of course.

Why It’s A Great Interview Question

Before we get to the Ruby quine hackery that I came up with, here is why I think it is a great question. You see, the good thing about this question is the fact that it is relatively small (doesn’t take too much time) but at the same time it is not binary (i.e. not yes/no or knows/doesn’t know or can do/can’t do). Here is how I see it potentially panning out and what it means.

You ask the question, and they draw up an answer for you almost instantly without batting an eyelid.

  • Clearly they have heard of this before, which shows they have an interest and some involvement in the wider programming community.
  • Having heard of it they were sufficiently intrigued to dig further, which shows an interest and passion for their craft and a willingness to invest time and tackle interesting/challenging problems.
  • If they explain it with gusto and a twinkle in their eyes :), you can be pretty sure they solved it themselves rather than looking it up, which shows they can think creatively and are actually able to solve the problems they tackle.
  • If they muddle their way through it and/or can’t really explain why/how something like their solution works, they probably looked it up rather than solving it themselves. This is not such a big deal, they have thought about it and can reproduce code they’ve seen and have a general understanding of how it works. Those are all good qualities.

Regardless, if you’re here, then as far as this question is concerned, you have at least a decent and potentially very good candidate on your hands – a positive result.

You ask the question and they’ve clearly never heard of it before, but they’re quickly able to arrive at a working solution.

  • You potentially have a closet superstar on your hands. They may not be as engaged in the community, since they haven’t heard the question before, but this is probably because they spent the majority of time doing what they love – coding. You next job is to find out if this is infact so.

Regardless, solving this question off-the-bat like this is praise-worthy – a positive result.

You ask the question and they’ve never heard of it, can’t come up with a solution, but are at least able to get towards the right track and can explain their thought process well and succinctly.

  • They’re likely not a superstar, but they do have some reasoning skills and they are a decent communicator which means they are still potentially a solid developer.

It may not be as positive a result as you would like – but it is not a total failure and it does tell you what kind of role this person would be more suited for if you were to hire them.

You ask the question and they’ve never heard of it, can’t solve it, and can’t come up with anything logical and end up confusing themselves repeatedly.

You can probably guess what the deal is with this situation. Total fail, you can still ask a question or two for due diligence, but chances are you have a dud on your hands.

See what I mean about being able to get a lot of information about a person from such a little question. I know you guys are already awesome – since you’re following this blog and if you’re not you better start :) – and would ace this question anyway. But for academic purposes, here is what I came up with using Ruby.

A Ruby Quine

The first version I did looked like this:

ruby def method;"def method;;end;puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]";end;puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]

Put it in a file and run it and we get the following output:

def method;"def method;;end;puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]";end;puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]

Perfect!

To things easier to understand, lets indent it a little bit (which will un-quinefy :) it, but doesn’t matter for study purposes):

```ruby def method; “def method;;end;puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]“; end;

puts method()[0, 11] + 34.chr + method + 34.chr + method()[11, method.length-11]```

The way it works is as follows. As some point you need to have a string which will contain all the code before and after itself, but will obviously not contain itself. It doesn’t really matter what you have before the string, but it does matter what you have after. You need to have repeated access to the string. You will then cut a substring from it which will be everything before the string itself. Following this, you need a quote (“) then the string itself then another quote and then cut everything else out of the string that you hadn’t cut before. You concatenate all this together and then output the whole thing. It makes it easier to have all of it on one line so you don’t have to deal with spaces. I realize it is not the best explanation, but you really do need to spend a little bit of time and think through this yourself – you will get it for sure.

Last thing left to do was to make my quine a little shorter (apparently with quines, the shorter they are the better, or so I’ve heard). Here is what I got:

ruby def s;"def s;;end;puts s()[0,6]+34.chr+s+34.chr+s()[6,s.length-6]";end;puts s()[0,6]+34.chr+s+34.chr+s()[6,s.length-6]

This can be made slightly shorter still, can you see how?

Here is a challenge if you’re up for it. Try and come up with a quine in Ruby that will output its source formatted/indented, perhaps using a heredoc. Is it even possible? Either way it’s good code kata.

If you can’t be bothered coming up with your own solution there is a whole bunch of them in different languages on the quine page, (but no Ruby ones that I can see).

Well, there we go, now the only thing left is to ask yourself how you think you would go, if got this kind of question in an interview?

Image by Neil Crosby