Translation description:

Sequences — a Pragmatic Approach

Original address:Proandroiddev.com/sequences-a…

Author:Tomek Pola ń ski

Sequences is a great tool that has a bit of a different approach to data sets than Android developers are used to. In my previous article, I compared the various ways to operate on sets, and now I want to give you an idea of when to use Sequences and when to use Lists.

When to use Sequences

Linking multiple operators

The biggest cause of performance loss when working with collections is cycling. The fewer iterations of collection elements, the better the performance. Here’s an example:

list
  .map { it + 1 }
  .filter { it % 2= =0 }
  .count { it < 10 } / / 286 mu s
Copy the code

decompile code

Collection<Integer> destination = new ArrayList<>(list.size());
Iterable<Integer> iterable = list;
Iterator<Integer> iterator = iterable.iterator();

while (iterator.hasNext()) {
    int it = iterator.next();
    destination.add(it + 1);
}

iterable = destination;
destination = new ArrayList<>();
iterator = iterable.iterator();

while (iterator.hasNext()) {
    int it = iterator.next();
    if (it % 2= =0) {
        destination.add(it);
    }
}

iterable = destination;
int count = 0;
iterator = iterable.iterator();

while (iterator.hasNext()) {
     int it = iterator.next();
    if (it < 10) { ++count; }}return count;
Copy the code

When you decompile the above code, you’ll find that the Kotlin compiler creates three while loops. You can use imperative programming to accomplish the same tasks in a single loop. Unfortunately, the compiler cannot optimize the code to this extent.

The trick for Sequences is that they share the same iterator — Sequences allow map to transform an element and then immediately pass that element to filter. Instead of waiting for all elements to loop through the map operation like lists, storing them in a new collection, and then iterating through the filter operation to retrieve elements from the new collection. By reducing the number of cycles, this Sequence provides us with a 26% performance improvement (List 286μs, Sequence 212μs) :

list
  .asSequence()
  .map { it + 1 }
  .filter { it % 2= =0 }
  .count { it < 10 } / / 212 mu s
Copy the code

Use the first {… } or last {… } operator

Using Sequences ** gives a small performance boost when using the first or last method that accepts a pre-judgment, but it gives a bigger performance boost when used in combination with other operators.

list
  .map { it + 1 }
  .first { it % 100= =0 } / / 232 mu s
Copy the code

Versions of Sequences are used:

list
  .asSequence()
  .map { it + 1 }
  .first { it % 100= =0 } / / 8 mu s
Copy the code

By comparison, we can see a 97% performance improvement.

When to use Lists

Set elements of a smaller magnitude

The Kotlin Lists API is still very effective when dealing with collection elements of a small order of magnitude (say less than 100), and you shouldn’t care if it requires 0.000007s (7μs) or 0.000014s (14μs). It’s usually not worth the effort to optimize.

Accessing an indexed element

Lists are indexed, which is why accessing items by index is very fast and has constant time complexity. Sequences, on the other hand, must work item by item until they reach the target project.

Note that the first() or last() methods that do not need to satisfy the pre-judgment condition internally use index to access the elements in the List — this is why they are faster relative to Sequences.

Return/passed to other functions

Elements are computed each time Sequences are iterated. Elements in Lists are counted only once and then stored in memory.

This is why you should never pass Sequences as arguments to a function: the function may iterate over them multiple times. It is recommended to transform Sequences to Lists before passing or using Lists altogether

If you really want to pass a sequence, you can use constrainOnce () – it allows only one walk through Sequences, and a second attempt throws an exception. However, I would not recommend this approach because it makes the code difficult to maintain.

You can also use this simple decision tree to decide whether to select a Sequences or Lists

Sequences can give you a nice performance boost if your application processes large amounts of data. However, you don’t need to change everything in your code that uses the List, but you really need to identify the bottleneck that affects performance and then fix it.

Translator has something to say

  • 1. Why am I translating this blog?

Sequences are a tool to optimize the performance of some of the operations in the set. They are actually similar to Stream in Java8, and some of us beginners may not be able to handle them well. We don’t know when Sequences should be used and when Lists should be used. It may be difficult for many people to find the difference between them, because the data sets we operate in ordinary times are of small magnitude and have similar performance losses. However, once they are at the magnitude of relatively big data, the difference between them will be very obvious. However, the author of this blog did a comparison between Sequences, Lists, and RxJava on the same data scale. I’m going to Declarative Kotlin: Lists, Sequences and RxJava. I’m going to Declarative Kotlin: Lists, Sequences and RxJava. So it is very important to choose the right way to operate the data set at the right time, so that is why I translated this blog.

  • 2. A few points about what to use Sequences.

First, the data set magnitude is large enough, so Sequences are recommended.

Second, frequent data operations are performed on the data set, similar to the chain operation of multiple operators. It is recommended to use Sequences.

For first{},last{} is recommended to use Sequences. In addition, careful friends will notice that when you use the first{} and last{} operators on a collection, our IDE tool will prompt you to suggest using Sequences instead of Lists. This is enough to see Kotlin’s IDE support. Which is an advantage, since Kotlin is the son of JetBrains.

  • 3, summarize

In fact, this blog only gives a general idea of when Sequences are used, but the details of why Sequences perform better than sets in the underlying implementation and more details of Sequences are just a passing pass, so my next blog will dive into Sequences in Kotlin, but this blog gives a general idea.

Welcome to the Kotlin Developer Alliance, where you can find the latest Kotlin technical articles. We will translate one foreign Kotlin technical article every week. If you like Kotlin, please join us ~~~