9
$\begingroup$

Given a subset s of Range[n] and two lists a and b, with Length[a] = Length[s] and Length[b] = n - Length[s], I would like to construct a new list shuffle[s,a,b], with members of a placed at positions given by s and members of b in the remaining positions, in the same order as in a and b.

For example, with n = 7, s = {2,3,6}, a = {a1,a2,a3} and b = {b1,b2,b3,b4}, shuffle[s,a,b] must be {b1,a1,a2,b2,b3,a3,b4}.

What comes to my mind is

l = Range[n];
Do[l[[s[[k]]]] = a[[k]],{k,Length[s]}];
t = Complement[Range[n],s];
Do[l[[t[[k]]]] = b[[k]],{k,Length[t]}]

but most likely there is a much more efficient solution.

$\endgroup$

9 Answers 9

11
$\begingroup$
s = {2, 3, 6};
a = {a1, a2, a3};
b = {b1, b2, b3, b4};

n = Length[a] + Length[b];
list = Range@n;
list[[s]] = a;
list[[Complement[Range[n], s]]] = b;
list

{b1, a1, a2, b2, b3, a3, b4}.

Or

n = Length[a] + Length[b];
ReplacePart[Range@n, 
 Thread /@ {s -> a, Complement[Range@n, s] -> b} // Flatten]

{b1, a1, a2, b2, b3, a3, b4}.

$\endgroup$
1
  • $\begingroup$ Fold[ReplacePart, Range@n, {Thread[s -> a], Thread[Complement[Range@n, s] -> b]}] $\endgroup$
    – cvgmt
    Commented Nov 19, 2023 at 12:10
8
$\begingroup$
a = {a1, a2, a3};
s = {2, 3, 6};
b = {b1, b2, b3, b4};

1.

We can use one of the many DataStructures introduced with V 12.1:

ds = CreateDataStructure["ExtensibleVector"];

Scan[ds["Append", #] &, b];

ds["Insert", ##] & @@@ Transpose[{a, s}];

Normal @ ds

{b1, a1, a2, b2, b3, a3, b4}

2.

Or the more conventional

b // RightComposition @@ MapThread[Insert, {a, s}]

{b1, a1, a2, b2, b3, a3, b4}

$\endgroup$
7
$\begingroup$

Using Ordering:

s = {2, 3, 6}; a = {a1, a2, a3}; b = {b1, b2, b3, b4};

#[[ Ordering@Join[s, Complement[Range@Length@#, s]] ]]&@Join[a, b]

(* {b1, a1, a2, b2, b3, a3, b4} *)
$\endgroup$
6
$\begingroup$

Using Fold:

n = 7;
s = {2, 3, 6};
a = {a1, a2, a3};
b = {b1, b2, b3, b4};

Fold[Insert[#1, First@#2, Last@#2] &, b, Transpose[{a, s}]]

{b1, a1, a2, b2, b3, a3, b4}

$\endgroup$
5
  • $\begingroup$ Great! Although I am sure this is optimal, still let me wait until tomorrow for other versions until accepting. $\endgroup$ Commented Nov 19, 2023 at 8:41
  • 1
    $\begingroup$ There are many ways of accomplishing list manipulation tasks in Mathematica. The 10-way challenge is on. $\endgroup$
    – Syed
    Commented Nov 19, 2023 at 8:44
  • $\begingroup$ What is this 10-way challenge? Never heard of it. $\endgroup$ Commented Nov 19, 2023 at 8:51
  • $\begingroup$ I believe the trend was started by @Nasser, where participants try to come up with at least 10 ways of solving a stated problem. $\endgroup$
    – Syed
    Commented Nov 19, 2023 at 8:55
  • 2
    $\begingroup$ I see. Sounds horrifying... $\endgroup$ Commented Nov 19, 2023 at 8:56
6
$\begingroup$

7.

ClearAll[sA]

sA = Module[{i$ = Complement[Range @ Length @ Join @ ##2, #]},
      SparseArray[{# -> #2, i$ -> #3}]] &;

Example:

s = {2, 3, 6}; a = {a1, a2, a3}; b = {b1, b2, b3, b4};

sA[s, a, b]

enter image description here

Normal @ sA[s, a, b]
 {b1, a1, a2, b2, b3, a3, b4}

8.

Normal[SparseArray[s -> a, {Length@Join[a, b]}]] /. 0 :> Last[b = RotateLeft@b]
 {b1, a1, a2, b2, b3, a3, b4}
$\endgroup$
3
$\begingroup$

Timings (cw)

|shuf0OP      |0.00746207|
|shufSyed     |0.561942  |
|shufeldo1    |0.707056  |
|shufeldo2    |0.632279  |
|shufcvgmt1   |0.00218898|
|shufcvgmt2   |0.0100496 |
|shufkglr7    |0.00446289|
|shufkglr8    |0.863815  |
|shufvindobona|0.00143314|
|shufkglr10   |0.00182783|

Just in case, let me reproduce the way I coded it, in case something is unsatisfactory please let me know (or edit the post accordingly, it is cw after all).

funtest[f_, n_, ss_] :=
 Module[{a, b}, 
  Mean[
   First[AbsoluteTiming[f[#, Array[a, Length[#]], Array[b, n - Length[#]]]]]&/@ss
  ]
 ]

n = 10000
ss = Table[Union@RandomSample[Range[n], RandomInteger[n]], {100}];

shuf0OP[s_, a_, b_] :=
 With[{n = Length[a] + Length[b]},
  With[{t = Complement[Range[n], s]},
   Module[{l = Range[n]},
    Do[l[[s[[k]]]] = a[[k]], {k, Length[s]}];
    Do[l[[t[[k]]]] = b[[k]], {k, Length[t]}];
    l
    ]
   ]
  ]

shufSyed[s_, a_, b_] := 
 Fold[Insert[#1, First@#2, Last@#2] &, b, Transpose[{a, s}]]

shufeldo1[s_, a_, b_] :=
 Module[{ds = CreateDataStructure["ExtensibleVector"]},
  Scan[ds["Append", #] &, b];
  ds["Insert", ##] & @@@ Transpose[{a, s}];
  Normal@ds
  ]

shufeldo2[s_, a_, b_] := 
 b // RightComposition @@ MapThread[Insert, {a, s}]

shufcvgmt1[s_, a_, b_] :=
 With[{n = Length[a] + Length[b]},
  Module[{list = Range@n},
   list[[s]] = a; list[[Complement[Range[n], s]]] = b;
   list
   ]
  ]

shufcvgmt2[s_, a_, b_] :=
 With[{n = Length[a] + Length[b]},
  ReplacePart[Range@n, 
   Thread /@ {s -> a, Complement[Range@n, s] -> b} // Flatten]
  ]

ClearAll[sA]
sA = Module[{i$ = Complement[Range@Length@Join@##2, #]}, 
    SparseArray[{# -> #2, i$ -> #3}]] &;
shufkglr7[s_, a_, b_] := Normal@sA[s, a, b]

shufkglr8[s_, a_, b_] :=
 Module[{bb = b},
  Normal[SparseArray[s -> a, {Length@Join[a, b]}]] /. 
   0 :> Last[bb = RotateLeft@bb]
  ]

shufvindobona[s_, a_, b_] :=
 #[[Ordering@Join[s, Complement[Range@Length@#, s]]]]&@Join[a, b]

ClearAll[pA]
pA = Module[{ab$ = Join @ ##2, p$}, 
  p$ = Join[#, Complement[Range @ Length @ ab$, #]]; 
  Permute[ab$, p$]
 ] &;
shufkglr10[s_, a_, b_] := pA[s, a, b]

TableForm@
 Table[{f, funtest[f, n, ss]},
  {f, {
       shuf0OP,
       shufSyed,
       shufeldo1,
       shufeldo2,
       shufcvgmt1,
       shufcvgmt2,
       shufkglr7,
       shufkglr8,
       shufvindobona,
       shufkglr10
      }
   }
  ]
$\endgroup$
3
$\begingroup$
a = {a1, a2, a3};
s = {2, 3, 6};
b = {b1, b2, b3, b4};

A variant of Syed's answer using Fold with Sequence

Fold[Insert[#1, Sequence @@ #2] &, b, Transpose[{a, s}]]

{b1, a1, a2, b2, b3, a3, b4}

$\endgroup$
2
$\begingroup$

9.

a$ = 0; b$ = 0;

Range @ Length @ Join[a, b] /.
   Alternatives @@ s :> a[[++a$]] /. _Integer :> b[[++b$]]
{b1, a1, a2, b2, b3, a3, b4}
$\endgroup$
3
  • $\begingroup$ This does not work with, say, a=Array[A,3], b=Array[B,4] $\endgroup$ Commented Nov 20, 2023 at 5:27
  • 1
    $\begingroup$ @მამუკაჯიბლაძე, right; it doesn't work if input lists a and b are not lists of atoms. I will post an update if I figure out a way to make it work for arbitrary lists. $\endgroup$
    – kglr
    Commented Nov 20, 2023 at 8:57
  • $\begingroup$ Would be nice - this version is conceptually very transparent, I would say. $\endgroup$ Commented Nov 20, 2023 at 9:39
2
$\begingroup$

10. (?)

pA = Module[{ab$ = Join @ ##2, p$}, 
    p$ = Join[#, Complement[Range @ Length @ ab$, #]]; 
    Permute[ab$, p$]] &;


pA[s, a, b]
{b1, a1, a2, b2, b3, a3, b4}
$\endgroup$
3
  • $\begingroup$ Why (?)?$\ \ \ $ $\endgroup$ Commented Nov 20, 2023 at 9:38
  • $\begingroup$ b/c I lost count:) $\endgroup$
    – kglr
    Commented Nov 20, 2023 at 9:39
  • 1
    $\begingroup$ Seems to be right. I've updated the timings. @vindobona is ahead by few milliseconds (these two solutions must be practically identical, imo) $\endgroup$ Commented Nov 20, 2023 at 9:47

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.