Skip like a frog!

12

1

Given an array of non-negative integers, your task is to only keep certain elements of it, as described below.

  • Let's say the array is [1, 3, 2, 4, 11, 5, 2, 0, 13, 10, 1].

  • First get the first element of the array, n. Keep the first n elements and discard the next one (discard the n+1th). The new array is [1, 2, 4, 11, 5, 2, 0, 13, 10, 1].

  • Then, you grab the element following the one removed and do the exact same thing. Reapplying the process, we get [1, 2, 11, 5, 2, 0, 13, 10, 1]

  • You repeat the process until you arrive outside the array's bounds / there are no elements left in the array. We stop because 11 is higher than the length of the array.

  • Now you should output the result.

Input / output may be taken / provided in any standard form. The array will never be empty, and will only contain non-negative integers. All standard loopholes are forbidden.

This is so the shortest code in bytes wins!


Test Cases

Input --> Output

[1, 2, 3, 4, 5] --> [1, 3, 4]

[6, 1, 0, 5, 6] --> [6, 1, 0, 5, 6]

[1, 3, 2, 4, 11, 5, 2, 0, 13, 10, 1] --> [1, 2, 11, 5, 2, 0, 13, 10, 1]

[2, 2, 2, 2, 2, 2] --> [2, 2]

[1, 2, 3, 1, 2, 3, 1, 2, 3] -> [1, 2]

[3, 1, 2, 4, 0] --> []*

* The last test case involves 0, so I decided to post the process such that it is clearer:

[3, 1, 2, 4, 0] --> [3, 1, 2, 0] --> [1, 2, 0] --> [1, 0] --> [0] --> [] )

(Inspired by this challenge by Erik the Outgolfer)

user70974

Posted 2017-08-21T19:03:16.803

Reputation:

I have written all the test cases completely by hand, please notify me if you think there is a mistake! – None – 2017-08-21T19:06:19.193

1Why is 2 removed in the first step instead of 3? – Leaky Nun – 2017-08-21T19:09:26.227

@LeakyNun My mistake. Correcting. Ping me if I made any other mistakes – None – 2017-08-21T19:10:06.280

suggested test case : [1, 2, 3, 1, 2, 3, 1, 2, 3] – Rod – 2017-08-21T19:55:18.543

@Rod Added. Thanks for the suggestion. – None – 2017-08-21T20:11:38.603

1So to clarify, when you move to your new "n", you always start from the beginning of the array to keep n elements? Not (as I thought at first glance) keep n elements where the first element is the n you are evaluating? – Brian J – 2017-08-22T13:10:48.990

@BrianJ Yes, you always remove the element from the beginning. – None – 2017-08-22T15:50:09.103

Are you downgoats sock? – Christopher – 2017-09-14T21:35:30.470

@Christopher2EZ4RTZ No, that's Evil Sheep. :P (Or TF2Goat)

– totallyhuman – 2017-09-14T21:39:29.867

Answers

1

Pyth, 18 bytes

#IgZlQB .(Q=Z@QZ)Q

Try it here.

Erik the Outgolfer

Posted 2017-08-21T19:03:16.803

Reputation: 38 134

Nope. – Leaky Nun – 2017-08-22T10:31:28.560

@LeakyNun And I thought I tested it enough! darn – Erik the Outgolfer – 2017-08-22T10:32:19.013

At least check the given testcases. – Leaky Nun – 2017-08-22T10:33:13.527

@LeakyNun sometimes I think code is giving me different results than what it actually does though...fixing...fixed (oh and btw I'm a bit lazy to remove the formatting off the test cases tbf) – Erik the Outgolfer – 2017-08-22T10:34:07.620

5

JavaScript (ES6), 45 bytes

f=(a,k=0,x=a[k])=>1/x?f(a.splice(x,1)&&a,x):a

Test cases

f=(a,k=0,x=a[k])=>1/x?f(a.splice(x,1)&&a,x):a

console.log(JSON.stringify(f([1, 2, 3, 4, 5]))) // --> [1, 3, 4]
console.log(JSON.stringify(f([6, 1, 0, 5, 6]))) // --> [6, 1, 0, 5, 6]
console.log(JSON.stringify(f([1, 3, 2, 4, 11, 5, 2, 0, 13, 10, 1]))) // --> [1, 2, 11, 5, 2, 0, 13, 10, 1]
console.log(JSON.stringify(f([2, 2, 2, 2, 2, 2]))) // --> [2, 2]
console.log(JSON.stringify(f([1, 2, 3, 1, 2, 3, 1, 2, 3]))) // -> [1, 2]
console.log(JSON.stringify(f([3, 1, 2, 4, 0]))) // --> []

Arnauld

Posted 2017-08-21T19:03:16.803

Reputation: 111 334

4

Haskell, 50 bytes

g.pure.(0:) is an anonymous function taking and returning a list of Ints, use as (g.pure.(0:))[1,2,3,4,5].

g.pure.(0:)
g(a,_:b:c)=g$splitAt b$a++b:c
g(a,_)=a

Try it online!

How it works

  • The function g takes a tuple argument representing a split list. a is the list of initial elements kept at the previous step, _ is the element to be discarded, b is the next element to be used as a length, and c is the remaining elements.
    • If there are enough elements in the second part of the tuple to select a b, then a new split is performed and g recurses. Otherwise, it halts with a as the result.
  • The anonymous function g.pure.(0:) starts it all by calling g with the tuple ([],0:l), where l is the input and 0 gets immediately discarded by g.
    • pure here uses the Applicative instance for (binary) tuples, and with the result type ([Int],[Int]) conveniently puts its argument as the second element in a tuple with [] as first element.

Ørjan Johansen

Posted 2017-08-21T19:03:16.803

Reputation: 6 914

3

Python 3, 59 bytes

f=lambda a,i=0:f(a[:a[i]]+a[a[i]+1:],a[i])if i<len(a)else a

Try it online!

Leaky Nun

Posted 2017-08-21T19:03:16.803

Reputation: 45 011

Impressive! I had a 65-byte non-recursive approach (in Python 2). – None – 2017-08-21T19:30:05.470

3

Haskell, 51 bytes

f s=s%s
s%(n:_)|(x,_:z)<-splitAt n s=(x++z)%z
s%_=s

Try it online! Example usage: f [1,2,3,4,5].

Laikoni

Posted 2017-08-21T19:03:16.803

Reputation: 23 676

2

Java 8, 68 bytes

This lambda accepts a mutable List<Integer> (supports remove(int), e.g. ArrayList). Output is mutated input. Assign to Consumer<List<Integer>>.

l->{for(int i=0,f=0;i<l.size();f^=1)i=f>0?l.remove(i)*0+i:l.get(i);}

Try It Online

The control flow for this problem is very annoying. Each iteration we have to remove an element and get the element at the next position, and both of these operations require a range check (and either may trigger program completion). One strategy is to carry out both operations in a single loop iteration, with the index update guarded by its own range check. Another strategy, which turned out to be shorter, is to alternate between the operations each loop iteration, which is what this solution does.

Jakob

Posted 2017-08-21T19:03:16.803

Reputation: 2 428

1

APL (Dyalog Classic), 32 bytes

1∘{n∇⍣(n≤≢w)⊢w←⍵/⍨(n←1+⍺⊃⍵)≠⍳≢⍵}

Explanation

1∘{                             } bind 1 as starting left argument (⍺)
                             ⍳≢⍵  generate indexes for right argument (⍵)
                   (n←1+⍺⊃⍵)      n is 1+item at position ⍺ 
              w←⍵/⍨         ≠     w is ⍵ with item at n removed
   n∇⍣(n≤≢w)⊢                     recurse with n as left and w as right arg if n <= length of w

Try it online!

Gil

Posted 2017-08-21T19:03:16.803

Reputation: 141

1

Perl 5, 38 + 1 (-a) = 39 bytes

splice@F,$p=$F[$p],1while$p<@F;say"@F"

Try it online!

Xcali

Posted 2017-08-21T19:03:16.803

Reputation: 7 671

1

Haskell, 99 bytes (88 without indentation)

f x y
 |y>=l=f x$l-1
 |e>=l=x
 |True=f (take e x ++ drop (1+e) x) e
 where e=x!!y
       l=length x

Giacomo Tecya Pigani

Posted 2017-08-21T19:03:16.803

Reputation: 111

I could probably save 1 byte using "1=1" instead of "True", also maybe the two spaces near "++" could be removed – Giacomo Tecya Pigani – 2017-08-22T19:33:01.210

1

VI, 31 25 bytes

O@0kdd<C-v><C-a>Y<C-v><C-x>gg@a<Esc>"add<C-a>Y<C-x>@a

<C-?> corresponds to Control + ?, and <Esc> to Escape obviously. Each of these count for 1 byte (see meta).

Input

The input file should contain 1 integer per line + 1 blank line at the end, example :

1
2
3
4
5
⁣

We can see each line of the input file as an array element, such as 1 :: 2 :: 3 :: 4 :: 5 :: [], like in some languages (caml for example).

Launch

You can start vi with the following command, and type the solution stroke by stroke :

vi -u NONE input

You can also use this one-liner :

vi -u NONE -c ':exec "norm O@0kdd\<C-v>\<C-a>Y\<C-v>\<C-x>gg@a\<Esc>\"add\<C-a>Y\<C-x>@a"' -c ":w output" -c ':q' input

This should produce a file output with the correct result from an input file input.

Explanations

To introduce the solution, I will first present a 19-bytes solution working only for arrays without 0. This solution uses a recursive macro, used with little modification in the final solution :

Yqa@0ddYgg@aquggY@a

Explanation of a partial solution

Y                       # yank first line (first integer + line break) to "0 register
 qa                     # start recording a macro ("a register)
   @0                   # jump n lines, where n is the content of the "0 register
     dd                 # delete the current line (n+1th line)
       Y                # yank current line (integer after the previously deleted line)
        gg              # go back to the first line
          @a            # recurse on macro "a"
            q           # finish recording the macro
             u          # cancel modifications done by the execution of the macro
              gg        # go back to the first line
                Y@a     # apply the recorded macro with first parameter equal to the first integer

The trick here is to use the "0 register to store the current integer (and the line break, very important). Therefore, the command @0 allows to jump n lines (call n the value of "0). If the jump exceeds the number of lines in the file, the macro will fail, so the program will stop (outside of the array bounds, as required).

But this solution does not work if the input contains 0. Indeed, if "0 register value equals 0, then @0 will jump one line (due to the line break), not 0 as we liked. So the next command (dd) won't delete the 0th integer, but the 1st (not correct).

A valid solution to handle the 0 is to always increment the integer before yanking it, and decrement it just after. Thus, the @0 command will jump n+1 lines (n is the current integer that have been incremented). A k command is then necessary to go to line n (previous line). Using this trick, a blank line is needed at the end of the input file, to avoid jumping outside of the array (thus, terminating the program), since we now always jump n+1 lines, before jumping to the previous line.

Explanation of the final solution

O                                                       # insert a new line at the beginning of the file, enter insert mode to write the macro content
 @0                                                     # jump n lines                                                       
   k                                                    # go to the previous line
    dd                                                  # delete this line
      <C-v><C-a>                                        # type Control+A (C-v is needed because we are in insert mode) to increment the current integer
                Y                                       # yank the incremented integer
                 <C-v><C-x>                             # decrement the current integer
                           gg                           # go to the first line
                             @a                         # recurse on macro "a"
                               <Esc>                    # exit insert mode : at this step, the first line of the file contains the macro content @0kdd^AY^Xgg@a
                                    "add                # copy @0kdd^AY^Xgg@a line to the register "a and delete the line
                                        <C-a>           # increment the first integer
                                             Y          # yank it (into "0)
                                              <C-x>     # decrement the first integer
                                                   @a   # apply macro in a" (initial @0 will jump n+1 lines, since we incremented the first integer before calling the macro)

Writing the macro content inside the file before registering it allows to save a few bytes :

  • avoids to write qa...q and undo all changes after registering
  • avoids :let @a="...")

Edits

#1

  • write the macro content on the first line (instead of last line)
  • change input (1 blank line at the end)
  • add one-liner to test in command-line

norbjd

Posted 2017-08-21T19:03:16.803

Reputation: 271

0

Pyth, 32 bytes

VlQIgNlQBK@QNI!K=QYBIgKlQB.(QK;Q

Try it online

Karan Elangovan

Posted 2017-08-21T19:03:16.803

Reputation: 179

Pyth can be much more elegant than that :) #VlQ.(Q@QN;Q does the job in 12 bytes, and I'm pretty sure it can be golfed even more – Dave – 2017-08-21T19:41:00.920

By keeping the old-school Pythonic approach you can do W<Zl=Q+<Q@QZ>Qh@QZ=Z@QZ)Q (25). pizzakingme's approach is much better though. – None – 2017-08-21T19:43:39.850

My solution still fails for cases that reduce to [0], it needs to be fixed up a bit before posting – Dave – 2017-08-21T19:44:45.447

Sorry, I'm still learning Pyth – Karan Elangovan – 2017-08-21T19:45:38.537

4@KaranElangovan nothing to apologize for, they're just trying to help you. – Leaky Nun – 2017-08-21T19:49:00.510

1Fixed for the final test case, it comes out to 15 bytes: #VlQ .(Q@QN)%;Q. Feedback from Pyth golfers would be welcome, I'm still learning too! – Dave – 2017-08-21T19:50:34.140

Oooh, the 15 byte one is broken too, because @ wraps around the array. – Dave – 2017-08-21T20:03:47.667

2This approach is invalid. Not only it doesn't print the result only, bur it also fails the test cases (the second last one at least). Can you please delete this answer / fix it? – None – 2017-08-21T20:15:57.770

0

C# (.NET Core), 74 bytes

n=>{for(int i=n[0];i<n.Count;){n.RemoveAt(i);i=i<n.Count?n[i]:n.Count+1;}}

Try it online!

This takes in a list of ints and modifies it. I have seen some Java answers that skirt around imports by using the fully qualified name in the Lambda argument definition. If this is not allowed, I can remove this answer.

jkelm

Posted 2017-08-21T19:03:16.803

Reputation: 441

If you're referring to the omission of parameter types in lambda definitions, that's allowed.

– Jakob – 2017-08-22T16:37:29.367

@Jakob I understand that. I just feel a little dirty for the System.Collections.Generic.List<int> instead of using System.Collections.Generic and adding that to the byte count. But I guess it isn't any different than using an array. – jkelm – 2017-08-22T16:45:35.147

Oh, I see. Well you could use using if you want; as long as the lambda itself doesn't rely on the statement you wouldn't have to include it in the byte count. Personally I always use fully-qualified names in test code just so that it's clear and easily verifiable what imports the lambda uses. – Jakob – 2017-08-22T16:51:43.043

0

R, 64 53 bytes

f=function(a,i=1,d=a[i]+1)"if"(is.na(d),a,f(a[-d],d))

Recursive function. Has one mandatory input, a, the list to skip over. i is the index of the number of things to jump over (defaults to 1), and d is the index of the next item after the required value has been removed, which is also the index of the item to be removed. Returns numeric(0), an empty vector, for empty output.

Try it online!

Ungolfed:

f <- function(a, i = 1, d = a[i] + 1) {
  if(is.na(d)) {   # d is NA if and only if a[i] is out of bounds
    a
  } else {
    f( a[-d], d, a[d] + 1 )   # a[-d] is a with the item at index d removed
  }
}

Giuseppe

Posted 2017-08-21T19:03:16.803

Reputation: 21 077