Skip to main content
added 792 characters in body
Source Link
C. E.
  • 71.2k
  • 6
  • 141
  • 269

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

Nearest is quite a lot faster than the naive approach, but not as fast as binary search. A drawback is that if we're inserting elements into the list, then we need to recreate the NearestFunction over and over since there is no way to update it.

sortedInsert3[list_, el_] := With[
  {nf = Nearest[list -> "Index"]},
  Insert[
   list,
   el,
   Last@nf[el]
   ]
  ]
sortedInsert3[list, #] & /@ values; // RepeatedTiming

{0.24, Null}

I tried running Nearest directly instead of creating a NearestFunction explicitly, but it turned out to be slower.

The second best solution that I've found is the most naive of them all, that you also mention in your question:

Sort[Append[list, #] & /@ values]; // RepeatedTiming

{0.095, Null}

I'm aware that Append does not actually append any value, but neither does Insert so I'm using it for comparison here. Sorting would take a bit longer perhaps if accounting for a large number of newly inserted elements, but as we can see sorting is very fast. If you have all the elements you want to insert available up front, then it's a no-brainer:

Sort@Join[list, values]; // RepeatedTiming

{0.000075, Null}

This reflects the fact that dynamically resizing lists is very slow, so we should typically always try to avoid that under any circumstance, including this one. (In Mathematica we also typically try to avoid any kind of looping, so we can look at it from that point of view too, Map being a type of iteration.)

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

Nearest is quite a lot faster than the naive approach, but not as fast as binary search. A drawback is that if we're inserting elements into the list, then we need to recreate the NearestFunction over and over since there is no way to update it.

sortedInsert3[list_, el_] := With[
  {nf = Nearest[list -> "Index"]},
  Insert[
   list,
   el,
   Last@nf[el]
   ]
  ]
sortedInsert3[list, #] & /@ values; // RepeatedTiming

{0.24, Null}

I tried running Nearest directly instead of creating a NearestFunction explicitly, but it turned out to be slower.

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

Nearest is quite a lot faster than the naive approach, but not as fast as binary search. A drawback is that if we're inserting elements into the list, then we need to recreate the NearestFunction over and over since there is no way to update it.

sortedInsert3[list_, el_] := With[
  {nf = Nearest[list -> "Index"]},
  Insert[
   list,
   el,
   Last@nf[el]
   ]
  ]
sortedInsert3[list, #] & /@ values; // RepeatedTiming

{0.24, Null}

I tried running Nearest directly instead of creating a NearestFunction explicitly, but it turned out to be slower.

The second best solution that I've found is the most naive of them all, that you also mention in your question:

Sort[Append[list, #] & /@ values]; // RepeatedTiming

{0.095, Null}

I'm aware that Append does not actually append any value, but neither does Insert so I'm using it for comparison here. Sorting would take a bit longer perhaps if accounting for a large number of newly inserted elements, but as we can see sorting is very fast. If you have all the elements you want to insert available up front, then it's a no-brainer:

Sort@Join[list, values]; // RepeatedTiming

{0.000075, Null}

This reflects the fact that dynamically resizing lists is very slow, so we should typically always try to avoid that under any circumstance, including this one. (In Mathematica we also typically try to avoid any kind of looping, so we can look at it from that point of view too, Map being a type of iteration.)

added 551 characters in body
Source Link
C. E.
  • 71.2k
  • 6
  • 141
  • 269

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

Nearest is quite a lot faster than the naive approach, but not as fast as binary search. A drawback is that if we're inserting elements into the list, then we need to recreate the NearestFunction over and over since there is no way to update it.

sortedInsert3[list_, el_] := With[
  {nf = Nearest[list -> "Index"]},
  Insert[
   list,
   el,
   Last@nf[el]
   ]
  ]
sortedInsert3[list, #] & /@ values; // RepeatedTiming

{0.24, Null}

I tried running Nearest directly instead of creating a NearestFunction explicitly, but it turned out to be slower.

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

Nearest is quite a lot faster than the naive approach, but not as fast as binary search. A drawback is that if we're inserting elements into the list, then we need to recreate the NearestFunction over and over since there is no way to update it.

sortedInsert3[list_, el_] := With[
  {nf = Nearest[list -> "Index"]},
  Insert[
   list,
   el,
   Last@nf[el]
   ]
  ]
sortedInsert3[list, #] & /@ values; // RepeatedTiming

{0.24, Null}

I tried running Nearest directly instead of creating a NearestFunction explicitly, but it turned out to be slower.

added 461 characters in body
Source Link
C. E.
  • 71.2k
  • 6
  • 141
  • 269

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica.

For the binary search idea, you could use Leonid Shifrin's fast, compiled binary search function here. It would look like this:

sortedInsert[list_, el_] := Insert[
  list,
  el,
  bsearchMax[list, el]
  ]

sortedInsert[2 Range[10], 13]

{2, 4, 6, 8, 10, 12, 13, 14, 16, 18, 20}

list = Sort@RandomInteger[100000, 10000];
values = RandomInteger[100000, 1000];
sortedInsert[list, #] & /@ values; // RepeatedTiming

{0.018, Null}

You may also want to check out the other solutions in that answer. As some have pointed out, the best complexity solution is not always the most performant solution, when implemented in Mathematica. For comparison with a very naive approach, however, we can clearly see that the above helps:

sortedInsert2[list_, el_] := Insert[
  list,
  el,
  LengthWhile[list, el > # &] + 1
  ]
sortedInsert2[list, #] & /@ values; // RepeatedTiming

{1.5954, Null}

added 217 characters in body
Source Link
C. E.
  • 71.2k
  • 6
  • 141
  • 269
Loading
Source Link
C. E.
  • 71.2k
  • 6
  • 141
  • 269
Loading