new fastutil user, FAQ?

128 views
Skip to first unread message

Daniel S.

unread,
May 27, 2020, 3:20:21 PM5/27/20
to fastutil

Hi Folks!

fastutil is an amazing lib. Thank you for creating it!!!!!! I discovered it a few weeks ago and it boosted my productivity!!!


Suggestion:
Although fastutil has a good documentation, getting started was sometimes a bit bumby. It would have helped me to have a quick read-over FAQ for new users which shows a few simple use cases that many users will want to try out first. I couldn't find one, and I still have a few open questions (see below).

During my adaption of fastutil, I've compiled a list of questions for which I couldn't find the answer straightforward (or not at all). I've also added some suggestions for changes/additions. This list can serve as a basis for such an FAQ.
The suggestions might be good or they might depend on personal taste, so if you don't like them I won't take up the cudgels for them; e.g. I might just have a different taste for naming conventions. Other suggestions can also be interpreted as a question, like "This is the best idea I had to solve some problem. Is there a better way to do it?" - check back with me if you have the feeling that some discussion might foster understanding what I'm after.


Here is the list:




1. How to sort an IntArrayList?
    Found it:
    IntArrayList list = ...;
    list.sort(IntComparators.NATURAL_COMPARATOR);


2.1. fastutil is cool. However, I wonder why I can't find IntArrayList.swap(i,j). I need that often. Is there a reason, or a better way to do a swap?



2.2. I sometimes like to use Lists of counters. It looks clumsy when I write intList.set(i, list.getInt(i) + 1). the maps have this excellent method addTo(int index, int incr). Can we have this for lists as well? It might not increase the performance, but it's definitely more readable like this: intList.addTo(i, 1).



2.3. Sometimes I need to set or addTo on ranges, or on all elements. I'd love to have an intList.set(int fromIndex, int toIndex, int value), and an addTo() of the same flavour. For even more convenience and readability, setAll() and addToAll() would be the ultimate gimmick.



2.4. Is there a way to transform each element of a list in the same way? e.g. with an Int2IntFunction, like intList.forEach((int k) -> 2 * k + 1); Would be pretty darn cool to have this!



3. What's the fastest way to read-iterate over an IntArrayList? - with iterator or with for (int i = 0; ...) { ... list.getInt(i) ... }? Is there anything faster that I'm not aware of?
Or does it not matter?
cf the same question on SO:
https://stackoverflow.com/questions/61855626/best-practice-for-iterating-over-fastutil-primitive-arraylists


4. What's slow and should be avoided in favour of good performance?
    I found this in Eclipse to help me:
    Window -> Preferences -> Java -> Compiler -> Errors/Warnings
    -> Potential Programming Problems -> Boxing and unboxing conversions
        -> set to Warning

    However, I'm sure it doesn't flag all cases of autoboxing, thus it has limited
    usefulness.

    Is there any other advice what to avoid and what to do?


5.1. How to presize a list?   /   5.2. How to add an element multiple times?
    Found presizing:
    IntArrayList list = new IntArrayList(n);
    list.size(n);

    5.2. remains: How to add an element multiple times to an existing list?

    Concerning 4.1.:
    Having 2 lines of code just for a presized list is clumsy. Is there a 1-line-way to make it size n, like new IntArrayList(n, true) or new IntArrayList(n, n)?


6. I saw IntArrayList.topInt(). Is there .bottomInt()? If not, it should be added. And maybe adjust the naming conventions, e.g. that of c++ std::vector: back() / front(), and maybe also data() or storage() instead of elements(). It took me some time to find elements().


7. How to best wrap (not copy) an int[] so it can be used as a collection or as an IntIterable?
    Found it:
    IntListIterator iter = IntIterators.wrap​(int[] array)


8. How to reverse the elements in a list? (NOT: how to sort with reverse order of a Comparator; that's something different)


9. I can use IntArrays.quickSort​(int[] x, int[] y) to sort two int[] arrays as if their elements at equal indices were one element. That's great and I missed this a lot in std Java.
How to do the same for an int[] and a long[], or for an IntArrayList and a LongArrayList? (or for two lists of the same type, e.g. two IntArrayLists; couldn't find that, just workaround with same style as in question 10.)


10. How to do a binary search on a LongArrayList?
I found the workaround LongArrays.binarySearch(longArrayList.elements(), 0, longArrayList.size(), key); // but that looks clumsy, lacks clarity


11. In addition to Int2IntMap.addTo(int k, int incr), I'd like to have Int2IntMap.addToExact(int k, int incr), which uses Math.addExact() for the addition.


12. It would make sense to allow usage of type specific lambdas on maps like we have it for lists. This is faster than int2intMap.int2IntEntrySet().fastForEach((Int2ObjectMap.Entry<MyObj> entry) -> {}), because it gets rid of the entry instance alltogether, and it is also much faster than the .forEach(BiConsumer<Integer, Integer>), because the latter style heavily involves autoboxing. Moreover the suggested way results in cleaner code, because it doesn't require the getIntKey(), getIntValue() methods:

    Int2IntOpenHashMap int2IntMap = null;

    // current way
    int2IntMap.int2IntEntrySet().fastForEach((Int2IntMap.Entry entry) -> {
        int key = entry.getIntKey();
        int value = entry.getIntValue();
        System.out.println(key + " => " + value);
    });

    // proposed way
    int2IntMap.forEach((IntIntBiConsumer) (int key, int value) -> {
        System.out.println(key + " => " + value);
    });

    // for this to work, we need the following interface
    @FunctionalInterface
    public interface IntIntBiConsumer extends BiConsumer<Integer, Integer> {

        public void accept(int t, int u);

        default public void accept(Integer t, Integer u) {
            accept(t.intValue(), u.intValue());
        }
    }


13. The documentation of fastutil is excellent. I still have a (very minor) critique:

The API doc is sometimes inherited to sublclasses. That's ok together with a note about this fact, like for IntArrayList.add(int index, int k): "Description copied from class: AbstractIntList...". However, this note is not shown in Eclipse, which had tricked me to believe that I can't use this method at all, because it says that the implementation was missing:




Very Best,
Daniel

Sebastiano Vigna

unread,
Oct 28, 2020, 1:30:08 PM10/28/20
to fastutil


Il giorno mercoledì 27 maggio 2020 alle 21:20:21 UTC+2 daniel...@gmail.com ha scritto:

Hi Folks!

Suggestion:

Although fastutil has a good documentation, getting started was sometimes a bit bumby. It would have helped me to have a quick read-over FAQ for new users which shows a few simple use cases that many users will want to try out first. I couldn't find one, and I still have a few open questions (see below).


Yes, I know reading the overview can be clumsy. Maybe we should have a "Getting started" section. 

2.1. fastutil is cool. However, I wonder why I can't find IntArrayList.swap(i,j). I need that often. Is there a reason, or a better way to do a swap?


Mmmh... no, simply, it is not in the interface. One can implement it (pull request?) 

2.2. I sometimes like to use Lists of counters. It looks clumsy when I write intList.set(i, list.getInt(i) + 1). the maps have this excellent method addTo(int index, int incr). Can we have this for lists as well? It might not increase the performance, but it's definitely more readable like this: intList.addTo(i, 1).

Usually people in these cases use array of counters. Why would you use a list?
 
2.3. Sometimes I need to set or addTo on ranges, or on all elements. I'd love to have an intList.set(int fromIndex, int toIndex, int value), and an addTo() of the same flavour. For even more convenience and readability, setAll() and addToAll() would be the ultimate gimmick.

These are all possibilities, but we would pollute the method namespace. It would become very difficult to find the basic methods.

2.4. Is there a way to transform each element of a list in the same way? e.g. with an Int2IntFunction, like intList.forEach((int k) -> 2 * k + 1); Would be pretty darn cool to have this!

I think there's something like that in the new collections, probably inherited. If not, we can think about it.

3. What's the fastest way to read-iterate over an IntArrayList? - with iterator or with for (int i = 0; ...) { ... list.getInt(i) ... }? Is there anything faster that I'm not aware of?

 

4. What's slow and should be avoided in favour of good performance?
    I found this in Eclipse to help me:
    Window -> Preferences -> Java -> Compiler -> Errors/Warnings
    -> Potential Programming Problems -> Boxing and unboxing conversions
        -> set to Warning

    However, I'm sure it doesn't flag all cases of autoboxing, thus it has limited
    usefulness.

    Is there any other advice what to avoid and what to do?

Note that fastutil deprecates all methods requiring boxing, so be sure to have warnings for deprecated methods.


    5.2. remains: How to add an element multiple times to an existing list?


A loop.
 


    Concerning 4.1.:
    Having 2 lines of code just for a presized list is clumsy. Is there a 1-line-way to make it size n, like new IntArrayList(n, true) or new IntArrayList(n, n)?


Nope.


6. I saw IntArrayList.topInt(). Is there .bottomInt()? If not, it should be added. And maybe adjust the naming conventions, e.g. that of c++ std::vector: back() / front(), and maybe also data() or storage() instead of elements(). It took me some time to find elements().

No, topInt() is just there to implement IntStack. data(), storage(), etc. it's just a matter of habitude.
 

7. How to best wrap (not copy) an int[] so it can be used as a collection or as an IntIterable?
    Found it:
    IntListIterator iter = IntIterators.wrap​(int[] array)


Yes. 

8. How to reverse the elements in a list? (NOT: how to sort with reverse order of a Comparator; that's something different)

In an array list, you can reverse the elements() array.

9. I can use IntArrays.quickSort​(int[] x, int[] y) to sort two int[] arrays as if their elements at equal indices were one element. That's great and I missed this a lot in std Java.
How to do the same for an int[] and a long[], or for an IntArrayList and a LongArrayList? (or for two lists of the same type, e.g. two IntArrayLists; couldn't find that, just workaround with same style as in question 10.)

No, but you can use elements(). It's dirty, but it works.

11. In addition to Int2IntMap.addTo(int k, int incr), I'd like to have Int2IntMap.addToExact(int k, int incr), which uses Math.addExact() for the addition.

You can subclass if you need that. 

12. It would make sense to allow usage of type specific lambdas on maps like we have it for lists.

These would be type-specific methods of Map? Sorry, I don't remember all the methods there. You want a type-specific forEach()?

13. The documentation of fastutil is excellent. I still have a (very minor) critique:

The API doc is sometimes inherited to sublclasses. That's ok together with a note about this fact, like for IntArrayList.add(int index, int k): "Description copied from class: AbstractIntList...". However, this note is not shown in Eclipse, which had tricked me to believe that I can't use this method at all, because it says that the implementation was missing:

Ouch. I don't know if there's an easy way out of these, lest of copying the documentation of the abstract class in the implementations.

Very Best,
Daniel


Thank you for all the comments, and sorry for answering so late.

seba 
Reply all
Reply to author
Forward
0 new messages