Part of Github Copilot with Kotlin

Kotlin with Copilot: Merge 2 lists

Sandy LaneSandy Lane

Video: Kotlin with Copilot: Merge 2 lists by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Kotlin: Merge Two Lists

list1 + list2 is all you need. Returns a new immutable list. Other options: flatten, plus, mutable list with addAll — pick based on whether you need mutation.

A trivial-looking puzzle that has surprisingly many "correct" answers. Copilot's default — using + — is the cleanest for the common case.

The Copilot prompt

fun main() {
  val list1 = listOf(1, 2, 3)
  val list2 = listOf(4, 5, 6)
  // Merge two lists into one

Copilot generates:

val mergedList = list1 + list2
println(mergedList)   // [1, 2, 3, 4, 5, 6]

Why + works

Kotlin defines operator fun <T> Collection<T>.plus(elements: Iterable<T>): List<T> in the standard library. So list1 + list2 returns a new immutable list containing list1's elements followed by list2's.

Both inputs are unchanged — neither list is mutated. That's the standard Kotlin convention: collection operations return new collections.

Other ways to merge

// Using listOf + spread (rare, no advantage)
val merged = listOf(*list1.toTypedArray(), *list2.toTypedArray())

// Using flatten (good for many lists)
val merged = listOf(list1, list2).flatten()

// Using plus (same as +)
val merged = list1.plus(list2)

// Mutable, mutate-then-build
val merged = mutableListOf<Int>().apply {
  addAll(list1)
  addAll(list2)
}.toList()

// Many lists, varargs
fun <T> mergeAll(vararg lists: List<T>): List<T> = lists.flatten()
val merged = mergeAll(list1, list2, list3)

For two lists: +. For many lists: flatten. Other options exist but rarely improve on these.

In-place merge (mutable)

If list1 is a MutableList and you want to modify it:

val list1 = mutableListOf(1, 2, 3)
val list2 = listOf(4, 5, 6)
list1.addAll(list2)
println(list1)   // [1, 2, 3, 4, 5, 6]

addAll(other) mutates the receiver. The receiver must be MutableList; the argument can be any Collection.

For MutableList += Iterable:

list1 += list2   // shorthand for list1.addAll(list2) when list1 is MutableList

Note: += on a var of List (immutable) reassigns to a new list:

var list = listOf(1, 2, 3)
list += listOf(4, 5)
// list now points to a new list [1, 2, 3, 4, 5]

Different mechanic — same syntax, different result. Watch the variable's type.

Removing duplicates while merging

val list1 = listOf(1, 2, 3)
val list2 = listOf(3, 4, 5)
val merged = (list1 + list2).distinct()   // [1, 2, 3, 4, 5]

// Or as a set:
val mergedSet = list1.toSet() + list2.toSet()   // {1, 2, 3, 4, 5}

distinct() preserves order; toSet() doesn't (unless using LinkedHashSet). For order-preserving deduplication, distinct() is what you want.

Interleaving instead of concatenating

Kotlin's standard library has zip for pair-wise alignment:

val list1 = listOf(1, 2, 3)
val list2 = listOf("a", "b", "c")
val zipped = list1.zip(list2)   // [(1, "a"), (2, "b"), (3, "c")]

For interleaving (1, "a", 2, "b", 3, "c"):

val interleaved = list1.zip(list2).flatMap { listOf(it.first, it.second) }

Slightly verbose. For a generic helper:

fun <T> interleave(a: List<T>, b: List<T>): List<T> =
  a.zip(b).flatMap { listOf(it.first, it.second) }

zip truncates to the shorter list. For "merge until both exhausted, padding with nulls," use zipWithNext or write explicit code.

Type compatibility

list1: List<Int> + list2: List<Int>List<Int>. list1: List<Number> + list2: List<Int>List<Number> (least upper bound). list1: List<Int> + list2: List<String> → won't compile.

Both lists must have a compatible element type. For mixed types, use Any explicitly:

val mixed: List<Any> = listOf(1, 2) + listOf("a", "b")

Possible, rarely useful.

Common mistakes

Mutating an immutable list. listOf(1, 2, 3).add(4) doesn't compile — List doesn't have add. Use mutableListOf or accept that you need a new list.

Forgetting that + returns a new list. list1 + list2 doesn't change list1. The result must be assigned: val merged = list1 + list2.

Inefficient many-list merging. (list1 + list2) + list3 + list4 creates intermediate lists. For more than a few, flatten is cleaner: listOf(list1, list2, list3, list4).flatten().

Mixing nullable elements. List<Int?> + List<Int> works; the result is List<Int?>. To filter nulls: (list1 + list2).filterNotNull().

Confusing + and +=. On val list: List<T>, += doesn't compile (immutable). On var list: List<T>, += reassigns. On val list: MutableList<T>, += mutates in place.

What's next

Episode 11: Initialize Firestore and save a Post. Set up Firebase Firestore in an Android app and persist a document.

Recap

list1 + list2 to merge — returns a new immutable List<T>. For many lists, listOf(l1, l2, l3).flatten(). For mutable receivers, addAll(other) or +=. To deduplicate, follow with .distinct(). zip for pair-wise alignment, then flatMap for interleaving.

Next episode: Firestore.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.