Fundamental programming patterns II — Collection

help developers to write cleaner code

Heaton Cai
4 min readDec 12, 2021

In the last article, I described different ways to implement a loop and they are essentially the pattern fold that gives an initial state and accumulates each element in a collection from first to last or from last to first. In this article, I’ll continue to explore more patterns about the operations of collections.

In order to show how simple these patterns are, I’ll implement a list from scratch with a very simple data structure.

Note: the examples in this article are written in Kotlin.

A Simple List

A list is simply composed of a head and another list as a tail. An empty list is a list without a head and tail.

The code

In the implementation, fold and foldRight are provided as the basic methods to iterate elements in a list. The factory methods are also provided for the convenience of list creation.

Fundamental Collection Operations

The following operations are basic patterns that are usually composed together to solve complex business requirements with simple and readable code.

Map

map is one of the most commonly used patterns, which transforms each element in a collection from a value to another, and results in a new collection.

Filter

filter is also one of the most commonly used patterns, which removes elements that don’t match a specific condition from a collection.

Reverse

reverse is a quite commonly used pattern, which reverses the elements in a collection.

GroupBy

groupBy is a very useful pattern, which groups the elements with the same key into different collections.

Concat

Concat is a frequently used pattern to merge two lists into one. I’ll use plus as the method name so that we can use the operator + to link two lists.

Flatten

flatten is the basis of flatMap .

Flat Map

flatMap is very useful when we need to combine the elements from two (or more) collections. The method is essentially a map plus a flatten .

Partition

partition is a useful pattern that split a collection into two by a specific condition.

Split

split is kind of the reversed operation of flatten , which equally split a collection into many collections. It is useful in parallel programming.

So far, we have discovered the common patterns of the collection operations. They mainly involve only one collection. In the next section, we’ll have a look at the patterns that involve two collections.

Fundamental Operations between Collections

Except for the listed pattern plus , there are many other useful patterns.

Exclude

This is a pattern that removes the elements that exist in another collection from the original collection.

Intersect

This is a pattern that selects the common elements into a collection from two collections.

Combine

This is a pattern that combines all the elements from two collections.

Zip

zip isn’t very commonly used, but it would be useful when we need to combine elements from two collections of the same size.

Operations among more than two collections are just combinations of operations between two collections. So they won’t be included here.

Performance

Now, we have gone through the fundamental patterns for the collection operations with implementations. However, all the code is for the purpose of easy understanding rather than best performance.

There are many ways to implement a collection type with different data structures that perform differently in different scenarios. Some are good for large size, some are good for small size, some are good for search, some are good for write, some are good for storage, some are good for transferring in networks. Thus, it is important to understand the difference so that we can use them properly to improve performance.

Luckily, collection types provided by most programming languages are good enough to handle almost all business cases. And many modern programming languages also provide well-performed implementations of the fundamental patterns for different collection types, some even with multithreading support to maximise the computing resources. Therefore, by choosing a powerful language that supports these patterns with sufficient performance, we could avoid spending time creating the existing wheels and build well-performed systems for the business quickly.

Summary

Business logic is essentially the combination of data transformations and data selections. By understanding these fundamental patterns and applying them with a modern language, we are able to implement most business rules with a good performance in just a couple of lines of code, so that the codebase stays small, consistent, and high-level abstract (without the running details), therefore more maintainable and changeable.

References

Appendix: Other Collection Patterns

Histories

All Combinations

--

--

Heaton Cai

16 years in the IT industry, passionate to share what I have learnt. All thoughts and opinions are original and maybe new. Free to share with the original link.