13
\$\begingroup\$

The goal of this challenge is to collect selected items in a list and move them to a certain location in the list.

As a visual example, take the input values (represented by black boxed integers) and a corresponding list of truthy values where true denotes the item is selected (represented by blue boxes, where T is truthy and F is falsy):

enter image description here

The first logical step is to separate the items marked truthy and not truthy into their corresponding lists. Note that relative order in each list must be maintained (i.e. the order of selected items must be 1,4,5, and the order of unselected items must be 2,3,6,7)!

enter image description here

The second logical step is given an index in the remaining list of unselected items, insert all selected items before the item at the given index. Assuming indexing starts at 0, suppose you want to insert the selection at index 3. This corresponds to the spot before the 7 box, so the selected items should be inserted before the 7.

enter image description here

The final solution is then 2,3,6,1,4,5,7.

Note that this logical diagram depicts one way this could be done; your program does not need to take the same logical steps as long as the output always produces the same observable result.

Input

Your program is given 3 inputs:

  1. A list of integers representing the items. This may be an empty list. This list will always consist of unique positive integers, not necessarily in sorted order (i.e. 5 will not be in the list twice).
  2. A list of truthy/falsy values with the same length as the list of items, where a truthy value represents that the item at the same index has been selected.
  3. An integer representing where to insert the selection. You may choose what the index of the first item of the list is as long as it is constant in every run of your program (e.g. the first item could be index 0 or index 1). Please specify which convention your program adheres to. This index should be in the range [starting_idx, ending_idx+1], i.e. it will always be a valid index. For the case index is ending_idx+1, the selection should be inserted at the end of the list. You may assume this integer will fit into your language's native integer type.

The input may come from any source desired (stdio, function parameter, etc.)

Output

The output is a list representing the final sequence of items. This can be to any source desired (stdio, return value, function output parameter, etc.). You are allowed to modify any of the inputs in-place (for example, given a modify-able list as a function parameter, and having your function operate in-place on that list).

Test cases

All of the following test cases assume 0-based indexing. I've used 0 and 1 to indicate falsy/truthy values respectively for the selection mask.

Test cases happen to have lists formatted as [a,b,c], but as long as your input lists represent a finite ordered sequence that's fine.

Input:

[]
[]
0

Output:

[]

Input:

[1,2,3,4,5,6,7]
[1,0,0,1,1,0,0]
3

Output:

[2,3,6,1,4,5,7]

Input:

[1,2,3,4,5,6,7]
[1,0,0,1,1,0,0]
0

Output:

[1,4,5,2,3,6,7]

Input:

[1,2,3,4,5,6,7]
[1,0,0,1,1,0,0]
4

Output:

[2,3,6,7,1,4,5]

Input:

[1,2,3,4,5,6,7]
[1,1,1,1,1,1,1]
0

Output:

[1,2,3,4,5,6,7]

Input:

[1,2,3,4,5,6,7]
[0,0,0,0,0,0,0]
5

Output:

[1,2,3,4,5,6,7]

Input:

[1,3,2,5,4,6]
[1,0,0,1,1,0]
3

Output:

[3,2,6,1,5,4]

Scoring

This is code golf; shortest answer in bytes wins. Standard loopholes are prohibited. You are allowed to use any built-ins desired.

\$\endgroup\$
6
  • \$\begingroup\$ Can the input and output be like '"1 2 3", "1 0 0", 1'? \$\endgroup\$
    – betseg
    Commented Jul 24, 2016 at 20:33
  • \$\begingroup\$ Yes, anything that represents two finite ordered integer sequences and an integer index in is fine. \$\endgroup\$ Commented Jul 24, 2016 at 20:48
  • \$\begingroup\$ Will the first array contain negative items or zero? \$\endgroup\$
    – Leaky Nun
    Commented Jul 25, 2016 at 1:07
  • \$\begingroup\$ I want to say no, but I'm also intrigued at what solution you have which requires this. So yes, you may assume the first list contains only positive integer. \$\endgroup\$ Commented Jul 25, 2016 at 2:26
  • \$\begingroup\$ @PeterTaylor no. I fixed it to read "A list of truthy/falsy values...". Is there a good name to describe the "type" of truthy/falsy values? Boolean-like? \$\endgroup\$ Commented Jul 25, 2016 at 15:19

8 Answers 8

10
\$\begingroup\$

MATL, 9 bytes

&)i:&)bwv

This solution accepts an array of T (true) and F (false) values as the second input. Also for the first test case, with empty arrays, it produces no output.

Try it Online! and a slightly modified version for all test cases.

Explanation

    % Implicitly grab the first two inputs
&)  % Index into the first array using the boolean, places two items on the stack:
    % 1) The values where the boolean is TRUE and 2) the values where it is FALSE.
i   % Explicitly grab the third input (N)
:   % Create an array from 1...N
&)  % Index into the FALSE group using this array as an index. Puts two items on the stack:
    % 1) The first N elements of the FALSE group and 2) other members of the FALSE group
b   % Bubble the TRUE members up to the top of the stack
w   % Flip the top two stack elements to get things in the right order
v   % Vertically concatenate all arrays on the stack
    % Implicitly display the result
\$\endgroup\$
5
\$\begingroup\$

Mathematica, 66 62 bytes

Saved 4 bytes from @MartinEnder.

a=#2~Extract~Position[#3,#4>0]&;##&@@@Insert[##~a~0,##~a~1,#]&

Anonymous function. Takes the 1-based index, the list, and the markers as input and returns the reordered list as output.

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

Haskell, 70 bytes

m%n=[e|(e,b)<-zip m n,b]
(l#s)p|(h,t)<-splitAt p$l%(not<$>s)=h++l%s++t

Usage example: ([1,2,3,4,5,6,7]#[True,False,False,True,True,False,False]) 3 -> [2,3,6,1,4,5,7].

How it works:

m%n=[e|(e,b)<-zip m n,b]        -- helper function, that extracts the elements of m
                                -- with corresponding True values in n
(l#s)p                          -- l: list of values
                                   s: list of booleans
                                   p: position to insert
  |                   (not<$>s) -- negate the booleans in s
                    l%          -- extract elements of l
          splitAt p             -- split this list at index p
   (h,t)<-                      -- bind h to the part before the split
                                -- t to the part after the split
     = h++l%s++t                -- insert elements at True positions between h and t
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 76 bytes

(a,b,c)=>(d=a.filter((_,i)=>!b[i]),d.splice(c,0,...a.filter((_,i)=>b[i])),d)
\$\endgroup\$
1
\$\begingroup\$

Jelly, 10 bytes

¬+\>⁵Ḥ³oỤị

Try it online!

How it works

¬+\>⁵Ḥ³oỤị  Main link.
            Arguments: x (list of Booleans), y (list of inputs), z (index)
¬           Logical NOT; invert all Booleans in x.
 +\         Take the cumulative sum.
            This replaces each entry with the number of zeroes up to that entry.
   >⁵       Compare the results with z.
            This yields 0 for the first z zeroes, 1 for all others. The behavior
            for ones is not important.
    Ḥ       Unhalve; multiply the previous resulting by 2.
     ³o     Take the element-wise logical NOT of x and the previous result.
            This replaces all but the first z zeroes in x with twos.
       Ụ    Grade up; sort the indices of the result according to the corr. values.
        ị   Retrieve the items of y at those indices.
\$\endgroup\$
0
\$\begingroup\$

C#, 132 bytes

int[]r(int[]a,bool[]b,int l){var x=a.Where((i,j)=>!b[j]);return x.Take(l).Concat(a.Where((i,j)=>b[j])).Concat(x.Skip(l)).ToArray();}

ungolfed:

    public static int[] r(int[] a,bool[] b,int l)
    {
        var x = a.Where((i, j) => !b[j]);
        return x.Take(l).Concat(a.Where((i, j) => b[j])).Concat(x.Skip(l)).ToArray();
    }

improvement ideas appreciated.

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

Python 3, 91 bytes

def f(a,x,i):b=[c for c,z in zip(a,x)if z<1];return b[:i]+[c for c in a if(c in b)<1]+b[i:]

where a is the elements/numbers list,x is the True/False list and i is the index.

Multiline version for improved readability:

def f(a,x,i):
    b=[c for c,z in zip(a,x)if z<1]
    return b[:i]+[c for c in a if(c in b)<1]+b[i:] 

How does it work?

The call to zip(a,x) results in a list of tuples where each of them contains the info: (element,0|1). Then a list comprehension is used to determine the elements that have a 0/False value associated and stores them in the variable b.

So [c for c,z in zip(a,x)if z<1] creates a list that contains all the elements that have a 0(False) value associated.

After that, the list of elements which have a True|1 value associated (which is determined by checking which elements of a are not present in b : [c for c in a if(c in b)<1]) is inserted in the list with all the elements that have a 0(False) value associated (list b) at the specified index i and the resulting list is returned.

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

Python 3, 106 93 bytes

def f(x,y,z):
 t,f=[],[]
 for n in range(len(x)):(f,t)[y[n]].append(x[n])
 f[z:z]=t
 return f

Older version:

def f(x,y,z):
 t,f=[],[]
 for n in range(len(x)):
  if y[n]:t+=[x[n]]
  else:f+=[x[n]]
 f[z:z]=t
 return f
\$\endgroup\$

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.