Kotlin Collections for C# Developers
In this blog
Recently, I learned Kotlin to develop an Android mobile application; my software development experience is primarily in C#. Throughout the learning process, I searched the internet for "Kotlin equivalent of [insert C# feature name]." The search proved to be an inefficient way to learn Kotlin. After all, with my C# experience, I knew many core programming concepts and needed to translate my existing knowledge into Kotlin code.
My goal for this article is to enable C# developers to learn Kotlin easily by having one place to look for the equivalent C# feature in Kotlin. Since comparing every aspect of C# to Kotlin would be lengthy, this article focuses on comparing Language-Integrated Query (LINQ) methods in C# to their equivalent Kotlin collection function.
LINQ methods are a central part of C#. If you have a data collection in code, you will likely use LINQ to process that data. Focusing on LINQ first will provide the most value for the C# developer who wants to learn Kotlin.
In this article, I review some of the most common LINQ methods and their equivalent function in Kotlin. A complete reference list of LINQ methods and their equivalent Kotlin collection functions is at the end.
Employee class example
Throughout this article, Employee
class is used for the C# examples:
public class Employee
{
public string Name { get; set; }
public int YearsWithCompany { get; set; }
}
This Employee
class has two properties: a string
(text) property for the employee's name and an int
(number) property for the years the employee has been with the company.
Use this equivalent class for the Kotlin examples:
data class Employee(val name: String, val yearsWithCompany: Int)
Use this list of employees for the C# examples:
var employees = new List<Employee>
{
new() { Name = "Tom", YearsWithCompany = 3 },
new() { Name = "Jane", YearsWithCompany = 6 }
};
Use this collection for the Kotlin examples:
val employees = listOf(Employee("Tom", 3), Employee("Jane", 6))
Filtering items based on a condition
One common LINQ method is Where()
. This method filters items in a collection that pass a given condition. An example of the Where()
method:
var seniorEmployees = employees.Where(employee => employee.YearsWithCompany > 5).ToList();
This example shows a collection of Employee
objects with a name field and a "years with the company" field. The Where()
method filters the collection of objects by only employees that have been with the company for more than five years. The filtered employees are stored in the variable called seniorEmployees
. The seniorEmployees
collection has one employee: Jane, who has been with the company for six years.
At the end of the example is the ToList()
method call. This call is necessary because the Where()
method does not return the expected collection of data (a collection of Employee
objects). It returns an object that has instructions to iterate over the initial collection to get the expected collection. Calling ToList()
runs what is known as deferred execution: you can get instructions via a LINQ method but then delay executing the instructions until necessary. The benefit of deferred execution is to increase code performance by chaining multiple LINQ methods and calling ToList()
once at the end to produce a single output collection.
The equivalent Kotlin function is filter()
. This is how you would use the filter()
function to implement the same logic as in the C# example:
val seniorEmployees = employees.filter { it.yearsWithCompany > 5 }
In this Kotlin example, there is a collection of Employee
objects like the C# example. The filter()
function filters the collection on the same condition as the C# example. (The it
keyword is an implicit variable representing an item in the collection.) Finally, the collection of filtered employees is stored in the variable called seniorEmployees
. It has the same employee, Jane, who has been with the company for six years.
Transforming each item in a collection
Another common LINQ method is Select()
. The method transforms each item in a collection into another type using the specified selector function parameter. Here is an example of the method:
var employeeNames = employees.Select(employee => employee.Name).ToList();
In this example, the Select()
method transforms each Employee
object in the collection into a new type by selecting the Name
property. The resulting collection, employeeNames
, is a list of strings containing each employee's name.
The Kotlin equivalent of Select()
is map()
:
val employeeNames = employees.map { it.name }
In this example, the map()
function transforms or maps the list of employees to the name
property and returns a list of strings like the C# example.
Returning the first item in a collection
The LINQ method FirstOrDefault()
in C# returns the first item in a collection or a default value if there are no items in the collection. An example:
var firstEmployeeInList = employees.FirstOrDefault();
In this example, the FirstOrDefault()
method gets the first Employee
object in the employees
collection. Then the first Employee
object is assigned to the variable firstEmployeeInList
. The first employee is Tom.
The Kotlin equivalent function is firstOrNull()
:
val firstEmployeeInList = employees.firstOrNull()
In this Kotlin example, the firstOrNull()
function gets the first Employee
object, like the C# example. The first employee is again Tom.
There is a useful overload of FirstOrDefault()
that takes a condition predicate parameter. This overload is like the Where()
method but only returns the first item that passes the condition. In Kotlin, use the firstOrNull()
function since it also has an overload that takes a condition predicate parameter.
Sorting items in a collection
The LINQ method OrderBy()
in C# sorts the items in a collection in ascending order using the key specified in the keySelector parameter. An example of OrderBy()
:
var sortedEmployees = employees.OrderBy(employee => employee.Name).ToList();
In this example, the OrderBy()
method sorts the items in the employees
collection by name, using the Employee
object's Name
property as the key. The employees in the returned collection, sortedEmployees
, are in the order "Jane" and "Tom."
The Kotlin equivalent function is sortedBy()
:
val sortedEmployees = employees.sortedBy { it.name }
In this example, the sortedBy()
function sorts the items in the employees
collection by the employee name, like the C# example. The sortedBy()
function takes a selector function parameter, like the OrderBy()
keySelector function parameter in C#.
The LINQ method OrderByDescending()
sorts the items in descending order. The Kotlin equivalent function is sortedByDescending()
.
Full LINQ to Kotlin collections reference
Below is an exhaustive list of LINQ methods and their equivalent Kotlin collection functions. In some cases, there is no equivalent Kotlin function.
The LINQ method list is based on the .NET 7 version. For more information on each LINQ method, go to the Microsoft documentation.
For more information on each Kotlin collection function, go to this documentation.
C# LINQ | Kotlin collections |
Aggregate | reduce |
All | all |
Any | any |
Append | plus, addAll |
AsEnumerable | asIterable |
Average | average |
Cast | ------------ |
Chunk | chunked |
Concat | plus, addAll |
Contains | contains, containsAll |
Count | count |
DefaultIfEmpty | ------------ |
Distinct | distinct |
DistinctBy | distinctBy |
ElementAt | elementAt |
ElementAtOrDefault | elementAtOrElse, getOrNull, getOrElse |
Empty | emptyList |
Except | subtract |
ExceptBy | ------------ |
First | first |
FirstOrDefault | firstOrNull, find |
GroupBy | groupBy |
GroupJoin | ------------ |
Intersect | intersect |
IntersectBy | ------------ |
Join | ------------ |
Last | last |
LastOrDefault | lastOrNull, findLast |
LongCount | count |
Max | maxOrNull |
MaxBy | maxByOrNull |
Min | minOrNull |
MinBy | minByOrNull |
OfType | filterIsInstance |
Order | sort |
OrderBy | sortBy, sortedBy |
OrderByDescending | sortByDescending, sortedByDescending |
OrderDescending | sortDescending |
Prepend | ------------ |
Range | ------------ Use x..y syntax to iterate over a range instead. (C# has range syntax too.) |
Repeat | ------------ Use collection constructor instead. |
Reverse | reversed, asReversed |
Select | map |
SelectMany | flatMap, flatten |
SequenceEqual | contentEquals, contentDeepEquals |
Single | single |
SingleOrDefault | singleOrNull |
Skip | drop |
SkipLast | dropLast |
SkipWhile | dropWhile |
Sum | sum, sumOf |
Take | take |
TakeLast | takeLast |
TakeWhile | takeWhile |
ThenBy | ------------ Use thenBy in kotlin.comparisons library. |
ThenByDescending | ------------ Use thenByDescending in kotlin.comparisons library. |
ToArray | ------------ |
ToDictionary | associate, associateBy |
ToHashSet | toHashSet |
ToList | asList |
ToLookup | ------------ |
TryGetNonEnumeratedCount | ------------ |
Union | union |
UnionBy | ------------ |
Where | filter |
Zip | zip |