19
\$\begingroup\$

In my previous code challenge, I asked you to write a function that tells you which of its lines has been removed.

The instructions were:

Write a function that contains five lines.

If you run the function as-is, it should return 0.

If you remove any one of the five lines and run the function, it should tell you which of the lines has been removed (e.g., if you remove the final line it should return 5).

Now, let's try something a teensy bit more difficult.

Follow the same rules as above, but this time, the function should return an array telling you which TWO lines have been removed.

So, for instance, if I remove lines 1 and 5, the return value should be [1,5], and if I remove lines 3 and 4, the return value should be [3,4].

Again, if no lines are removed, the function should return 0. Bonus points if you can also handle the one-line-removed case, but it's not strictly necessary that you do so.

Can you make use of helper functions? Yes, but only if you have to. A single self-contained function that pulls this off is the ideal.

As with the last challenge, the highest upvoted solution wins. I'll pick the winner in a week, or sooner if no new submissions have been received in 24 hours.

\$\endgroup\$
6
  • 3
    \$\begingroup\$ Is returning an empty list OK if no lines are removed, or does it have to be the number 0? \$\endgroup\$ Commented Dec 30, 2013 at 15:08
  • 1
    \$\begingroup\$ is the return line in the function one of the lines that can be removed? \$\endgroup\$
    – 6160
    Commented Dec 30, 2013 at 15:32
  • 11
    \$\begingroup\$ May we expect that tomorrow the version "three-lines" will be posted? \$\endgroup\$
    – Howard
    Commented Dec 30, 2013 at 15:33
  • \$\begingroup\$ Must the function literally return the array or can it edit a variable in the global scope .etc? I do not think this is possible in 5 lines whilst actually returning due to not being able to look ahead as all lines must return incase the return is removed. Unless there are some language quirks like automatic returning functions I don't know about. \$\endgroup\$ Commented Dec 30, 2013 at 15:33
  • \$\begingroup\$ I think you should also provide the link to your previous question, as for someone who is interested and has not seen it. \$\endgroup\$
    – DroidDev
    Commented Dec 31, 2013 at 10:39

15 Answers 15

16
\$\begingroup\$

Perl

sub foo {
    @a = (2..5);
    @a = grep $_ != 2, (@a ? @a : (1..5));
    @a = grep $_ != 3, (@a ? @a : (1..5));
    @a = grep $_ != 4, (@a ? @a : (1..5));
    @a = grep $_ != 5, (@a ? @a : (1..5));
}

This actually works for any number of lines removed (as long as it's not all the lines, that is), and can be trivially extended to more than 5 lines. No helper functions are used, and it even uses only one statement per line. It relies on the fact that, in the absence of an explicit return statement, the return value of a Perl function is the value of the last statement in it.

Note that (in list context) this code returns an empty list rather than the number 0 if no lines have been deleted. This could be fixed (e.g. by appending "@a ? @a : 0;" to the last line), but would make the code uglier. In any case, in scalar context it does return the number of deleted lines, which will be 0 if no lines have been removed. ;-)

\$\endgroup\$
9
\$\begingroup\$

Ruby

Similar to the Perl version, but in Ruby. I return 0 if no lines are deleted as requested, but I agree it makes the code uglier and doesn't quite make sense as a return value.

def which_lines_removed(arr = [*1..5])
  arr -= [1]
  arr -= [2] 
  arr -= [3] 
  arr -= [4] 
 (arr -= [5]).empty? ? 0 : arr
end

If an empty array is acceptable as the return value when no lines are deleted, the code looks like this:

def which_lines_removed(arr = [*1..5])
  arr -= [1]
  arr -= [2] 
  arr -= [3] 
  arr -= [4] 
  arr -= [5]
end

Both methods work for any number of lines deleted between 0 and 5.

\$\endgroup\$
4
\$\begingroup\$

JavaScript, 152 characters golfed

function t() {
    var fa = (f + '').match(/\d/g)
    var ra = []
    for (var i = 0; i < 5; i++) {
        if (fa.indexOf(i + '') < 0) ra.push(i + 1)
    }
    return ra
}

function f() {
    0; return t()
    1; return t()
    2; return t()
    3; return t()
    4; return t()
}

Golfed:

function t(){for(a=[],i=0;++i<5;)if((f+'').indexOf(i)<0)a.push(i+1);return a}function f(){
return t(0)
return t(1)
return t(2)
return t(3)
return t(4)
}

Self contained (but ugly):

function f() {
    0; var ra = []; for (var i = +![]; i < 5; i++) if ((f + '').match(/\d/g).indexOf(i + '') < +![]) ra.push(i); return ra
    1; var ra = []; for (var i = +![]; i < 5; i++) if ((f + '').match(/\d/g).indexOf(i + '') < +![]) ra.push(i); return ra
    2; var ra = []; for (var i = +![]; i < 5; i++) if ((f + '').match(/\d/g).indexOf(i + '') < +![]) ra.push(i); return ra
    3; var ra = []; for (var i = +![]; i < 5; i++) if ((f + '').match(/\d/g).indexOf(i + '') < +![]) ra.push(i); return ra
    4; var ra = []; for (var i = +![]; i < 5; i++) if ((f + '').match(/\d/g).indexOf(i + '') < +![]) ra.push(i); return ra
}

Basically exploits function toString by numbering each line. Note that you actually have to remove the line because of this (commenting it out will not work).

This actually works for any number of lines removed! It will return an array of the lines removed, or an empty array if none have been removed. (I could easily change that to return zero (by replacing return ra with return ra || 0), but I like the empty array solution since it would be more useful in the real world.)

For example, removing the first line returns [1], and removing everything but the first line returns [2,3,4,5]. (Of course, it doesn't work if you remove all lines ;-))

\$\endgroup\$
3
\$\begingroup\$

Ruby

def f
    a = [ 2, 3, 4, 5 ]
    defined?(a) ? a = a.select { |num|    num != 2 } : a = [ 1, 3, 4, 5 ]
    defined?(a) ? a = a.select { |num|    num != 3 } : a = [ 1, 2, 4, 5 ]
    a = a.select { |num|    num != 4 }
    (a = a.select { |num|    num != 5 }) == [] ? a = 0 : a
end

How this works: my idea was: create an array, and on each line, remove a specific value. So, on the first line, I actually have the array [ 1, 2, 3, 4, 5], with the element 1 removed. At the second line, if a is already defined, remove the element 2. Otherwise, create a new array with the element 2 removed. Do the same for line 3. At line 4, you can be sure that there is already an array created, so just remove element 4. At line 5, first remove element 5, and if a is then an empty array, return 0. Otherwise, return a.

\$\endgroup\$
3
\$\begingroup\$

Python

f=lambda:{1,2,3,4,5}-{
1,
2,
3,
4,
5,
} or 0

Returns 0 if no line is removed, otherwise returns the removed lines. You can remove 1 to 5 lines, except the 0th and 6th line ;-).

\$\endgroup\$
2
\$\begingroup\$

JavaScript, self-contained, works for 0, 1, 2 removed lines (607  315 186 chars)

live demo

Abusing JS variable hoisting and global leaking, like in the other challenge :)

function(r){
r.shift();
r.splice(r.indexOf(2),1)
r.splice(r.indexOf(3),1);a=b=1;if(this.a&&this.b)return r
var a;r.splice(r.indexOf(4),1);b=1;if(this.b)return r
var b;r.pop();return r[0]?r:0
}

to be called with the array [1,2,3,4,5] as parameter.

315 chars

function(r){
var a;
var b;
var c;a=1;b=2;d=4;e=5;for(i in(z="abde".split("")))if(y=this[z[i]])r.push(y);return r.length?r:0
var d;a=1;b=2;c=3;e=5;for(i in(z="abce".split("")))if(y=this[z[i]])r.push(y);return r.length?r:0
var e;a=1;b=2;c=3;d=4;for(i in(z="abcd".split("")))if(y=this[z[i]])r.push(y);return r.length?r:0
}

to be called with an empty array as parameter.



non-golfed version

(also works for 3 and 4 lines removed):

function(r){
var a;b=c=d=e=1;if(this.b)r.push(2);if(this.c)r.push(3);if(this.d)r.push(4);if(this.e)r.push(5);return r.length?r:0;
var b;a=c=d=e=1;if(this.a)r.push(1);if(this.c)r.push(3);if(this.d)r.push(4);if(this.e)r.push(5);return r.length?r:0;
var c;a=b=d=e=1;if(this.a)r.push(1);if(this.b)r.push(2);if(this.d)r.push(4);if(this.e)r.push(5);return r.length?r:0;
var d;a=b=c=e=1;if(this.a)r.push(1);if(this.b)r.push(2);if(this.c)r.push(3);if(this.e)r.push(5);return r.length?r:0;
var e;a=b=c=d=1;if(this.a)r.push(1);if(this.b)r.push(2);if(this.c)r.push(3);if(this.d)r.push(4);return r.length?r:0;
}

to be called with an empty array as parameter.

\$\endgroup\$
2
\$\begingroup\$

JavaScript:

var f = function(){
    1
    2
    a=[];for(i=0;i++<6;){if((f+'').indexOf(i)<0){a.push(i)}}return a.length?a:0;3
    a=[];for(i=0;i++<6;){if((f+'').indexOf(i)<0){a.push(i)}}return a.length?a:0;4
    a=[];for(i=0;i++<6;){if((f+'').indexOf(i)<0){a.push(i)}}return a.length?a:0;5
}

fiddle

\$\endgroup\$
2
\$\begingroup\$

Javascript

(function (i){

i += .1;     // line 1
i += .02;    // line 2
i += .003;   // line 3
i += .0004;  // line 4
i += .00005; // line 5

return (Math.round((.12345-i)*100000)/100000+'').match(/([1-5])/g) || 0 })(0)

Call it what you like, but I think it's pretty.

Lets you know which lines were removed (1 or more), or 0 if no lines are removed. All 5 lines can be removed.

EDIT:

Because it was brought to my attention that my code might actually consists of 6 lines, and is in violation of the rules, I adjusted it to the following:

(Math.round((.12345 - (new (function(){

    this.i = isFinite(this.i) ? this.i + .1 : .1 ;
    this.i = isFinite(this.i) ? this.i + .02 : .02;
    this.i = isFinite(this.i) ? this.i + .003 : .003; 
    this.i = isFinite(this.i) ? this.i + .0004 : .0004;
    this.i = isFinite(this.i) ? this.i + .00005 : .00005; 

})().i || 0) )*100000)/100000+'').match(/([1-5])/g) || 0

The same applies -- it will return an array of removed lines ranging from 1-All or 0 if none.

\$\endgroup\$
7
  • \$\begingroup\$ Not sure if its going to help but I noticed some others doing it, so.. Mine is 149 characters with spacing & 128 without. \$\endgroup\$
    – logic8
    Commented Dec 31, 2013 at 13:42
  • \$\begingroup\$ Since it's not a code-golf, you don't need to remove the whitespace. \$\endgroup\$
    – Timtech
    Commented Dec 31, 2013 at 14:28
  • 1
    \$\begingroup\$ The "return" line is within the function, so the function actually has six lines of code, which violates the rules of the challenge. \$\endgroup\$
    – jawns317
    Commented Dec 31, 2013 at 15:34
  • \$\begingroup\$ @jawns317, I am unsure how a "line" is defined. Could someone please provide a clear definition? \$\endgroup\$
    – logic8
    Commented Dec 31, 2013 at 22:20
  • \$\begingroup\$ @logic8 Remove function(){ and } (and any helper functions). Count the number of lines. \$\endgroup\$
    – Doorknob
    Commented Dec 31, 2013 at 22:59
1
\$\begingroup\$

Common Lisp

(defun which-lines-are-removed (&aux (x (list 1 2 3 4 5))) 
  (setq x (remove-if #'(lambda (x) (eql x 1)) x))
  (setq x (remove-if #'(lambda (x) (eql x 2)) x))
  (setq x (remove-if #'(lambda (x) (eql x 3)) x))
  (setq x (remove-if #'(lambda (x) (eql x 4)) x))
  (setq x (remove-if #'(lambda (x) (eql x 5)) x))
)

It works for removal of 1-4 lines. If you remove all lines it will return the same as if you remove none.

NB: Having ending parenthesis on it's own line is considered bad style, but since other languages has end and } I assume it is allowed.

\$\endgroup\$
1
\$\begingroup\$

Python

def function(a = [1,2,3,4,5]):
    delete(a, len(a)-5)#1
    delete(a, len(a)-4)#2
    delete(a, len(a)-3);print a if len(a)==2 else '',#3
    delete(a, len(a)-2);print a if len(a)==2 else '',#4
    delete(a, len(a)-1);print a if len(a)==2 else '',#5

def delete(a, i):
    del a[i]
    return a

It works for all lines - but only if two are deleted. If only one line is deleted then it will print the deleted line and line 5. If too many lines are deleted it won't print anything.

This uses a helper function because the del keyword can't be used in a line with a ;(as far as I know)

Basically, each line deletes itself in the array that is declared in the constructor, then if enough lines have been deleted the array is printed.

This function misses the spec in two ways:

  1. it doesn't print 0 if it is run as-is(it assumes the last two lines have been commented and so prints 4, 5
  2. It assumes that print and return are interchangeable
\$\endgroup\$
1
  • \$\begingroup\$ Will doing print '' not generate an extra newline character though? \$\endgroup\$
    – SimonT
    Commented Dec 30, 2013 at 21:17
1
\$\begingroup\$

Déjà Vu

Works for removing any number of lines (as long as you leave at least one line)

local line n:
    try:
        dup
    catch stack-empty:
        dup set{ 1 2 3 4 5 }
    delete-from swap n

func which-gone:
    line 1
    line 2
    line 3
    line 4
    line 5
\$\endgroup\$
0
\$\begingroup\$

R

I have another version in R which I think is better (but uses a helper function):

trick <- function(sym, value) {
  assign(sym, value, envir=parent.frame())
  values <- unlist(as.list(parent.frame()))
  if(length(values)==5) 0 else which(!1:5 %in% values)
}

reportRemovedLines <- function(){
  trick("a", 1)
  trick("b", 2)
  trick("c", 3)
  trick("d", 4)
  trick("e", 5)
}

Or one can avoid using the helper function by defining it as a default argument (works identically but is less readable -- however, it does not use a "separately defined" helper function):

funnyVersion <- function(trick = function(sym, value) {
  assign(sym, value, envir=parent.frame())
  values <- unlist(as.list(parent.frame()))
  if(length(values)==5) 0 else which(!1:5 %in% values)
}){
  trick("a", 1)
  trick("b", 2)
  trick("c", 3)
  trick("d", 4)
  trick("e", 5)
}

Both reportRemovedLines() and funnyVersion() work with any number of lines removed - except if you remove all lines (in that case, they will return NULL). They actually return the line numbers, not just print them - as in R, the value of the last expression evaluated within a function will automatically be returned.

How does it work? The trick is in the trick function which takes all objects from its "parent environment" (i.e., environment of the function that calls it), puts their values together in a vector, and returns, which values from 1 to 5 are not represented.

\$\endgroup\$
0
\$\begingroup\$

JavaScript (136/166 chars)

A smaller version with some values declared at the beginning:

function(){b=[1,2,3,4,5],i=0
    b.splice(0,1);i++
    b.splice(1-i,1);i++
    b.splice(2-i,1);i++
    b.splice(3-i,1);i++
    b.splice(4-i,1);i++
return b}

A self-contained version (you don't need to pass anything - the b argument is there so I can check if b is defined with ||)

function(b){
    b=[2,3,4,5],i=1
    b=b||[1,2,3,4,5],i=i||0,b.splice(1-i,1);i++
    b=b||[1,2,3,4,5],i=i||0,b.splice(2-i,1);i++
    b.splice(3-i,1);i++
    b.splice(4-i,1);i++
return b}

Yes, both have return statements, but that is only fair if I am competing with languages with implicit return.

\$\endgroup\$
3
  • \$\begingroup\$ True, it's easier in those languages, but it's not impossible in JS. I don't consider either of these to have met the constraints of the challenge, since your 136-char version has seven lines of code within the function, and your 166-char version has six. The fact that you have code on the same line as the opening or closing brackets doesn't mean that code isn't part of the function. \$\endgroup\$
    – jawns317
    Commented Jan 1, 2014 at 11:37
  • \$\begingroup\$ What about the answers that use helpers? \$\endgroup\$
    – Jencel
    Commented Jan 1, 2014 at 15:15
  • \$\begingroup\$ Helper functions are explicitly permitted. But the function from which lines are removed should contain five lines of code. \$\endgroup\$
    – jawns317
    Commented Jan 1, 2014 at 20:53
0
\$\begingroup\$

R

A simple version (not foolproof as you will get an error if you remove line 5):

doit <- function() setdiff(1:5, c(
       1,
       2,
       3,
       4,
       5
    ))

And a foolproof version:

doit<-function() setdiff(1:5, scan(text="
1
2
3
4
5
"))

It works with any number of lines removed (except if you remove all the lines), and can easily be extended to more than 5 lines. Running it "as is" will return integer(0) which is conceptually similar to returning just 0. Returning an actual 0 would make it uglier and longer but would not be complicated.

Finally, a version using magic:

Helper function:

dysfunction <- function(E){
    FUN <- function(){}
    e <- substitute(E)
    e[[1]] <- as.name("list")
    nb <- quote(setdiff(as.list(1:5), x))
    nb[[3]] <- e
    body(FUN) <- nb
    FUN
    }

The actual function:

df <- dysfunction({
1
2
3
4
5
})
\$\endgroup\$
0
\$\begingroup\$

C++

void function(int & i)
{
        i=i|1;
        i=i|2;
        i=(i|4);
        i=(i|8);
        i=(i|16);
} 


int[] func2(int i)
{
    int arr[]={0,0};
    int k=0,l=1;
    for(int j=1;j<=16;j*=2,l++)
    {
        if((i&j)==0)
        {
             arr[k++]=l;
        }
    }
    return arr;
}

How to use: call the function with i and use func2 for understanding that what function is telling.

If you change the line int arr[]={0,0} to int arr[]={0,0,0,0,0} it will also work for all five lines, it is also handline one line remove test case automatically, what i am doing is simply using a bits of a variable as a flag for each line....

\$\endgroup\$
6
  • \$\begingroup\$ Doesn't function have six lines, not five? \$\endgroup\$
    – Cel Skeggs
    Commented Jan 30, 2014 at 22:29
  • \$\begingroup\$ return is not part of that, u can see other answers also.... it's language dependency \$\endgroup\$ Commented Jan 31, 2014 at 4:21
  • \$\begingroup\$ See this comment from the author of the challenge on one of the other entries: "True, it's easier in those languages, but it's not impossible in JS. I don't consider either of these to have met the constraints of the challenge, since your 136-char version has seven lines of code within the function, and your 166-char version has six. The fact that you have code on the same line as the opening or closing brackets doesn't mean that code isn't part of the function. – jawns317" \$\endgroup\$
    – Cel Skeggs
    Commented Jan 31, 2014 at 5:59
  • \$\begingroup\$ check it now and tell me ur responce \$\endgroup\$ Commented Jan 31, 2014 at 9:46
  • \$\begingroup\$ C doesn't work like that. It gives a compiler error. Probably you're thinking of C++. \$\endgroup\$
    – Cel Skeggs
    Commented Feb 1, 2014 at 5:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.