12
\$\begingroup\$

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)

\$\endgroup\$
  • \$\begingroup\$ I have written all the test cases completely by hand, please notify me if you think there is a mistake! \$\endgroup\$ – user70974 Aug 21 '17 at 19:06
  • 1
    \$\begingroup\$ Why is 2 removed in the first step instead of 3? \$\endgroup\$ – Leaky Nun Aug 21 '17 at 19:09
  • \$\begingroup\$ @LeakyNun My mistake. Correcting. Ping me if I made any other mistakes \$\endgroup\$ – user70974 Aug 21 '17 at 19:10
  • \$\begingroup\$ suggested test case : [1, 2, 3, 1, 2, 3, 1, 2, 3] \$\endgroup\$ – Rod Aug 21 '17 at 19:55
  • 1
    \$\begingroup\$ So 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? \$\endgroup\$ – Brian J Aug 22 '17 at 13:10

13 Answers 13

1
\$\begingroup\$

Pyth, 18 bytes

#IgZlQB .(Q=Z@QZ)Q

Try it here.

\$\endgroup\$
  • \$\begingroup\$ Nope. \$\endgroup\$ – Leaky Nun Aug 22 '17 at 10:31
  • \$\begingroup\$ @LeakyNun And I thought I tested it enough! darn \$\endgroup\$ – Erik the Outgolfer Aug 22 '17 at 10:32
  • \$\begingroup\$ At least check the given testcases. \$\endgroup\$ – Leaky Nun Aug 22 '17 at 10:33
  • \$\begingroup\$ @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) \$\endgroup\$ – Erik the Outgolfer Aug 22 '17 at 10:34
5
\$\begingroup\$

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]))) // --> []

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

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.
\$\endgroup\$
3
\$\begingroup\$

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!

\$\endgroup\$
  • \$\begingroup\$ Impressive! I had a 65-byte non-recursive approach (in Python 2). \$\endgroup\$ – user70974 Aug 21 '17 at 19:30
3
\$\begingroup\$

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

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

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.

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

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!

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

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

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

Try it online!

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

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
\$\endgroup\$
  • \$\begingroup\$ I could probably save 1 byte using "1=1" instead of "True", also maybe the two spaces near "++" could be removed \$\endgroup\$ – Giacomo Tecya Pigani Aug 22 '17 at 19:33
1
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

Pyth, 32 bytes

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

Try it online

\$\endgroup\$
  • \$\begingroup\$ 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 \$\endgroup\$ – Dave Aug 21 '17 at 19:41
  • \$\begingroup\$ 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. \$\endgroup\$ – user70974 Aug 21 '17 at 19:43
  • 4
    \$\begingroup\$ @KaranElangovan nothing to apologize for, they're just trying to help you. \$\endgroup\$ – Leaky Nun Aug 21 '17 at 19:49
  • 1
    \$\begingroup\$ Fixed 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! \$\endgroup\$ – Dave Aug 21 '17 at 19:50
  • 2
    \$\begingroup\$ This 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? \$\endgroup\$ – user70974 Aug 21 '17 at 20:15
0
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ If you're referring to the omission of parameter types in lambda definitions, that's allowed. \$\endgroup\$ – Jakob Aug 22 '17 at 16:37
  • \$\begingroup\$ @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. \$\endgroup\$ – jkelm Aug 22 '17 at 16:45
  • \$\begingroup\$ 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. \$\endgroup\$ – Jakob Aug 22 '17 at 16:51
0
\$\begingroup\$

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
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy