Dart: Collection for Function

In Dart, you can use the for keyword inside collections like Lists, Sets, and Maps to efficiently manipulate, transform, and filter data. This powerful feature allows you to generate new collections by applying rules and conditions to existing data, all within the same collection declaration.

Think of it like going through a list of tasks and deciding which ones to tackle based on certain conditions, like prioritizing urgent tasks over less important ones. Instead of handling each task one by one, you can apply a rule to decide what to do with the entire list in one step. That’s essentially what Dart’s collection for function helps you do—it lets you apply conditions and transformations on the fly while building collections.

So why should you care about this? By using for in collections, you can make your code shorter, more readable, and more efficient.

Let’s explore how this feature works and how it can enhance your Dart programming skills.

Basic Usage of Collection for Function

The collection for function allows you to create and manipulate collections in a concise, readable manner. It lets you use a for loop directly inside a collection literal (like a List, Set, or Map) to generate or transform elements.

To use the collection for, you can place the for loop inside the collection’s square brackets [] (for Lists), curly braces {} (for Sets), or key-value pairs for Maps. This allows you to iterate through an existing collection and perform transformations or filtering while creating a new collection.

Here’s the general syntax:

[for (var item in collection) expression]

Example: Transforming a List of Numbers

Let’s consider a list of numbers. With the collection for, we can create a new list where each number is squared.

void main() {

  List<int> numbers = [1, 2, 3, 4, 5];
  List<int> squares = [for (var num in numbers) num * num];

  print(squares);  // Output: [1, 4, 9, 16, 25]

}

In this example, we start with a list of numbers, numbers. Using the collection for, we iterate through each number in the list (for (var num in numbers)) and calculate its square (num * num). The result is a new list, squares, which contains the squared values of the original numbers.

This is a clean, efficient way to transform collections without having to write lengthy loops or separate operations. It’s especially helpful when you want to apply the same transformation to all elements in a collection.

Using Collection for with Lists

The collection for function can be used inside list literals to filter, transform, and generate elements efficiently. It’s especially useful when you want to perform an operation on each element of an existing list and generate a new list with the desired elements.

When using the for loop inside a list, you can conditionally add elements to the list based on certain criteria or perform transformations like squaring numbers, filtering out certain values, or modifying elements before adding them.

Here’s the syntax for using for inside a list:

List<Type> newList = [for (var item in oldList) expression];

You can also add a condition inside the for to filter out elements that don’t meet your criteria:

List<Type> newList = [for (var item in oldList) if (condition) expression];

Example: Creating a List of Even Numbers

Suppose you have a list of integers, and you want to create a new list containing only the even numbers from the original list. You can achieve this using the collection for and an if condition.

void main() {

  List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

  // Create a list of even numbers
  List<int> evenNumbers = [for (var num in numbers) if (num % 2 == 0) num];

  print(evenNumbers);  // Output: [2, 4, 6, 8]

}

In this example, the list numbers contains the integers from 1 to 9. Using the collection for, we iterate through each element of the numbers list. The condition if (num % 2 == 0) filters out the odd numbers, and only even numbers are added to the new list evenNumbers.

Using collection for with conditions inside a list helps you write cleaner, more readable code when working with collections. It makes operations like filtering and transformation simpler and more elegant.

Using Collection for with Sets

The collection for function can also be used in a set literal. Sets in Dart are collections of unique items, so when using the for loop inside a set, the result will automatically remove duplicates. This is especially useful when you want to transform elements and guarantee that only unique values are stored.

In a set, we can use the collection for function in a similar way to lists, iterating over a collection and adding transformed items. However, since sets don’t allow duplicates, any repeated values will be automatically discarded.

Here’s the syntax for using for inside a set:

Set<Type> newSet = {for (var item in oldCollection) expression};

The main advantage of using a set is that if the transformed or added items are duplicates, only one copy will be kept, ensuring the uniqueness property of sets is maintained.

Example: Creating a Set of Squares of Numbers

Suppose you have a list of numbers and you want to generate a set of squares, ensuring no duplicates. Even if there were duplicate results from the transformation, the set will automatically handle that by keeping only unique squares.

void main() {

  List<int> numbers = [1, 2, 3, 4, 2, 3, 4];

  // Create a set of squares
  Set<int> squares = {for (var num in numbers) num * num};

  print(squares);  // Output: {1, 4, 9, 16}

}

In this example, the numbers list contains some repeated numbers (2, 3, and 4). Using the collection for, we create a new set squares that stores the squares of each number in numbers. The transformation num * num computes the square of each number, and because we’re using a set, any duplicate squares (e.g., 4 and 9 appearing more than once) will be removed automatically. The output is {1, 4, 9, 16}, where only unique squares are retained.

Using collection for with sets makes it easy to generate sets from other collections while ensuring that only unique elements are included. This is especially useful for tasks like filtering duplicates or performing set-based operations in a concise and efficient manner.

Using Collection for with Maps

In Dart, maps are collections of key-value pairs, and using the collection for function inside a map literal allows you to generate key-value pairs dynamically. This is useful when you want to transform or filter data into a map format, such as creating a map from a list of objects or values.

When using for inside a map, you iterate over a collection and assign a key and a value for each item. The key-value pairs are generated based on the expression inside the for loop.

Here’s the syntax for using for inside a map:

Map<KeyType, ValueType> newMap = {for (var item in oldCollection) keyExpression: valueExpression};

The result is a map where each item is transformed into a key-value pair. You can control both the key and value based on the iteration logic.

Example: Creating a Map of Students and Their Grades

Suppose you have a list of student objects, each containing a name and a score. You want to create a map where the key is the student’s name, and the value is their score.

void main() {

  // List of students and their scores
  List<Map<String, dynamic>> students = [
    {'name': 'Samantha', 'score': 90},
    {'name': 'Robert', 'score': 85},
    {'name': 'Hermione', 'score': 95}
  ];

  // Create a map of student names and their grades
  Map<String, int> studentGrades = {
    for (var student in students) student['name']: student['score']
  };

  print(studentGrades);  // Output: {Samantha: 90, Robert: 85, Hermione: 95}

}

The students list contains maps, each with a name and a score for each student. Using the collection for, we iterate over each student in the students list. For each iteration, we create a key-value pair where the key is student['name'] and the value is student['score']. The result is a new map, studentGrades, where the student’s name is the key and their score is the value. The output will be: {Samantha: 90, Robert: 85, Hermione: 95}, showing each student’s name and corresponding score.

Using collection for with maps is a powerful way to transform collections of data into structured key-value pairs with minimal code. It’s particularly useful when you need to dynamically generate a map from a list of objects or values, streamlining the process of data manipulation in Dart.

Using Collection for with Conditional Logic

You can combine the for loop with conditional logic to filter and include items in a collection based on specific conditions. This powerful feature allows you to iterate through a collection and add only those elements that meet certain criteria.

Combining for with if

In Dart, you can place an if statement inside the for loop when using the collection for. This enables you to conditionally include elements in the collection. If the condition is met, the item is added to the collection; otherwise, it is skipped.

Here’s the syntax for using if inside a collection for:

collection = [for (var item in collection) if (condition) item];

The if statement filters out elements that don’t meet the condition and includes only those that pass.

Example: Filtering Numbers Greater Than 5

Let’s say you have a list of numbers, and you want to create a new list that only contains the numbers greater than 5. You can use the for loop with if to filter the numbers.

void main() {

  // Original list of numbers
  List<int> numbers = [2, 5, 8, 1, 9, 3, 7];

  // Create a new list containing only numbers greater than 5
  List<int> filteredNumbers = [for (var num in numbers) if (num > 5) num];

  print(filteredNumbers);  // Output: [8, 9, 7]

}

The numbers list contains a mix of integers. Using the collection for with if, we iterate through each number in the numbers list. The if condition if (num > 5) ensures that only numbers greater than 5 are included in the new list. The resulting filteredNumbers list contains [8, 9, 7], which are the numbers greater than 5 from the original list.

This combination of for and if in collections is a convenient way to filter and manipulate data, ensuring that you can easily create new collections that meet specific requirements. Whether you’re working with lists, sets, or maps, this technique makes it simple to work with conditional data in Dart.

Combining Collection for with Functions

You can combine the collection for loop with functions to transform, filter, or modify data passed to them. This is useful when you want to encapsulate the logic of data manipulation within a function, making your code more modular and reusable.

Passing Data Through Functions:

By passing data such as a list, set, or map to a function, you can use the collection for to iterate over the data and apply logic like transformations or filters. This allows you to separate the logic of manipulating collections from the rest of your program, improving readability and maintainability.

Here’s the syntax for using the collection for inside a function:

List<Type> functionName(List<Type> inputData) {

  return [for (var item in inputData) if (condition) item];

}

Example: Using a Function to Generate a List of Names Starting with ‘A’

Let’s create a function that takes a list of names and returns a new list containing only those names that start with the letter ‘A’. We will use the collection for inside the function to filter the names.

// Function that returns names starting with 'A'
List<String> filterNamesStartingWithA(List<String> namesList) {
  return [for (var name in namesList) if (name.startsWith('A')) name];
}

void main() {

  // List of names
  List<String> names = ['Samantha', 'Robert', 'Adam', 'Hermione', 'Angela'];

  // Call the function and print the result
  List<String> filteredNames = filterNamesStartingWithA(names);
  print(filteredNames);  // Output: [Adam, Angela]

}

We first define a list of names that includes various names, some starting with ‘A’ and some not. The function filterNamesStartingWithA takes a list of names (namesList) as an argument and filters out those names that start with ‘A’. The collection for is used inside the function to iterate through the namesList. The if (name.startsWith('A')) condition ensures that only names starting with the letter ‘A’ are included in the new list. The function returns a new list containing the names [Adam, Angela] that start with ‘A’, and we print this list.

Combining the collection for with functions provides a clean and powerful way to manipulate data. It allows you to filter, transform, and process collections based on certain conditions or logic, all within a reusable function, improving code structure and readability.

Nested Collection for

Sometimes, you need to deal with nested collections such as lists within lists, sets inside maps, or maps inside lists. In these situations, you can use nested collection for loops to iterate over the inner collections and perform operations like flattening or transformation.

Using for Inside Nested Structures

A nested collection for is a powerful way to handle complex data structures. It allows you to iterate over multiple levels of collections (like a list of lists or a map of lists) and create a new collection based on your logic.

Here’s the general syntax for using a for loop inside nested collections:

[

  for (var subList in inputData)
    for (var item in subList) 
      item

];

This creates a new collection by iterating through each sub-collection (like a list inside a list), and then iterating through the individual items in those sub-collections.

Example: Flattening a List of Lists

Let’s say you have a list of lists (a two-dimensional list) and you want to flatten it into a single list. Using nested for loops inside the collection literal, we can iterate over the inner lists and combine all the items into a new flat list.

void main() {

  // List of lists
  List<List<int>> listOfLists = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
  ];

  // Flatten the list of lists using nested collection for
  List<int> flattenedList = [

    for (var subList in listOfLists) 
      for (var number in subList) 
        number

  ];

  // Print the flattened list
  print(flattenedList);  // Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

}

We have a listOfLists, which is a list containing other lists of integers. The nested collection for is used to iterate over each subList (the inner lists) inside listOfLists. Then, we iterate over each number in the subList. As a result, the flattenedList contains all the elements from each of the inner lists, creating a single list: [1, 2, 3, 4, 5, 6, 7, 8, 9].

By using nested collection for, you can efficiently handle more complex collections and generate new collections with ease. It helps simplify the code and allows you to manipulate nested data structures in a concise and readable manner.

Using a Traditional for Loop in Collections

Sometimes you might want to use the traditional for (int i = 0; i < ...; i++) loop instead of for in. You can absolutely do that inside Dart collections.

Using the index i gives you more control—for example, when accessing multiple lists at the same time, skipping every other item, or building a list from scratch.

Syntax:

[for (int i = 0; i < list.length; i++) list[i] * 2]

Example: Doubling Each Number Using Index

Let’s say you have a list of numbers and you want to double each one. By using a traditional for loop, you can access the index and apply any custom logic.

void main() {

  List<int> numbers = [10, 20, 30];

  List<int> doubled = [
    for (int i = 0; i < numbers.length; i++) numbers[i] * 2
  ];

  print(doubled);  // Output: [20, 40, 60]

}

Here, we loop through the list using an index and double each number. It works just like the for in version but gives you access to the index if you need it.

Example: Repeating “Meow” Five Times

Let’s say you want to create a list that contains the word “Meow” five times. Instead of looping through another list, you can simply use a traditional for loop to repeat something a specific number of times.

void main() {

  List<String> catSounds = [
    for (int i = 0; i < 5; i++) 'Meow'
  ];

  print(catSounds);  // Output: [Meow, Meow, Meow, Meow, Meow]

}

Here, we’re not using an existing list—we’re just using the loop to generate values. This is great for repeating something or generating a sequence without needing a source list.

Example: Mixing Two Lists Using Index

Let’s say you have two lists—one with programming languages and one with animals—and you want to combine them into fun phrases like "Python Tiger", "Java Fox", and so on. A traditional for loop with an index is perfect for this.

void main() {

  List<String> languages = ['Python', 'Java', 'C++'];
  List<String> animals = ['Tiger', 'Fox', 'Eagle'];

  List<String> mixed = [
    for (int i = 0; i < languages.length; i++) '${languages[i]} ${animals[i]}'
  ];

  print(mixed);  // Output: [Python Tiger, Java Fox, C++ Eagle]

}

Here, we use the index i to access elements from both lists at the same time. This lets us pair items and create something new and fun from two different lists.

Example: Skipping Every Other Item

Let’s say you have a list of natural languages and you want to make a new list with only every other language. A traditional for loop with an index lets you do that easily by increasing the index by 2 each time.

void main() {

  List<String> languages = ['Spanish', 'Swahili', 'Japanese', 'Zulu', 'French', 'Arabic'];

  List<String> skipped = [
    for (int i = 0; i < languages.length; i += 2) languages[i]
  ];

  print(skipped);  // Output: [Spanish, Japanese, French]

}

Here, the loop skips every second item by using i += 2 instead of i++. It’s great when you want to filter a list based on position, not value.

Conclusion

In this article, we explored the power and flexibility of the collection for function in Dart. This feature allows you to efficiently generate, transform, and filter elements in collections like lists, sets, and maps, all while maintaining a clean and concise code structure.

By using the collection for, you can:

  • Transform data: Quickly modify items within a collection.
  • Filter elements: Conditionally include or exclude items based on certain criteria.
  • Simplify code: Avoid using verbose loops or manual checks when constructing collections.

Whenever you need to iterate over a collection and generate new elements in a clear and efficient way, reach for the collection for. It’s especially useful when working with dynamic data, and it ensures that your code stays easy to understand and maintain. Whether you’re building complex data structures or simply need to filter or transform a list, the collection for function will keep your code both powerful and elegant.