{ "green" "blue" "purple" } [ length ] map-sort
] unit-test
{ 1 { 1 2 3 4 } } [ 1 { 4 2 1 3 } [ dupd + ] map-sort ] unit-test
+
+{ 0 } [ 0 { 1 } bisect-right ] unit-test
+{ 1 } [ 1 { 1 } bisect-right ] unit-test
+{ 1 } [ 2 { 1 } bisect-right ] unit-test
+
+{ 0 } [ 0 { 1 } bisect-left ] unit-test
+{ 0 } [ 1 { 1 } bisect-left ] unit-test
+{ 1 } [ 2 { 1 } bisect-left ] unit-test
-USING: arrays assocs kernel kernel.private sequences
-sequences.private sorting ;
+USING: arrays assocs kernel kernel.private locals math
+math.order sequences sequences.private sorting ;
IN: sorting.extras
: argsort ( seq quot: ( obj1 obj2 -- <=> ) -- sortedseq )
[ map ] curry keep zip
[ { array } declare first-unsafe ] sort-with
[ { array } declare second-unsafe ] map ; inline
+
+:: bisect-left ( obj seq -- i )
+ 0 seq length [ 2dup < ] [
+ 2dup + 2/ dup seq nth-unsafe obj before?
+ [ swap [ nip 1 + ] dip ] [ nip ] if
+ ] while drop ;
+
+:: bisect-right ( obj seq -- i )
+ 0 seq length [ 2dup < ] [
+ 2dup + 2/ dup seq nth-unsafe obj after?
+ [ nip ] [ swap [ nip 1 + ] dip ] if
+ ] while drop ;
+
+: insort-left ( obj seq -- seq' )
+ [ bisect-left ] 2keep swapd insert-nth ;
+
+: insort-right ( obj seq -- seq' )
+ [ bisect-right ] 2keep swapd insert-nth ;