frptools / collectable

High-performance immutable data structures for modern JavaScript and TypeScript applications. Functional interfaces, deep/composite operations API, mixed mutability API, TypeScript definitions, ES2015 module exports.
MIT License
273 stars 14 forks source link

[sorted-map] Insert function? #68

Closed tokland closed 6 years ago

tokland commented 6 years ago

Package sorted-map has a set function to add a key/value to an existing map:

set<K, V, U> (key: K, value: V, map: SortedMapStructure<K, V, U>): SortedMapStructure<K, V, U>

But I cannot find a function to insert a value somewhere in the middle of the map. Something like:

insert<K, V, U> (index: number, key: K, value: V, map: SortedMapStructure<K, V, U>): SortedMapStructure<K, V, U>

Am I missing something? Thanks.

axefrog commented 6 years ago

Hey, yep you're missing something :-)

The sorted map is self-sorting - that is, you define the sorting criteria when you construct the map, and it sorts items according to those criteria. If you could just insert items into any index, it wouldn't necessarily be sorted. If you don't specify any sorting criteria, the items are sorted in order-of-insertion.

You have two options:

  1. You could use a list and a map; use the map to store an index, then insert the item into the associated index in the list.

  2. Store the index as a field in the object you're adding to the sorted map, then specify the index field as the sorting criteria, like so:

import { empty, set } from '@collectable/sorted-map';

const comparator = (a, b) => a.value.index - b.value.index;
const sortedMap = empty(comparator);
const updatedMap = set('key', { id: 1, index: 10 }, sortedMap);

To change the index, just remove the item and re-insert it.

tokland commented 6 years ago

Somehow, I expected that, even though the map uses order-of-insertion by the default, I could still insert a value anywhere in the tree without too much hassle. Tbh I did not check the implementation details :) Option no 1 I had already considered, no 2 it's an approach I hadn't thought of, I'll check how it works. Thanks for the detailed answer!

axefrog commented 6 years ago

No worries! Also, note that you'll experience unexpected behaviour if you mutate any fields that are used as sorting criteria before removing the associated object from the map. If you intend to be able to modify your object without having to remove it from the map first, I'd suggest using a wrapper object, e.g.:

const objectToInsert = { index: 10, value: myObject }