Search code examples
arraysfilterballerina

How to Filter Values from a Nilable Array Using Query Expressions


I want to select specific fields from a record with the record type Student[]? in Ballerina.

In the code below, classes[className] has the type Student[]?.

Student[] is iterable but Student[]? is not.

Why is that and how does it figure that out?

import ballerina/io;

type Student record {|
    string firstName;
    string lastName;
    int age;
    string address;
    string className;
|};

function getStudentNames(map<Student[]> classes) returns map<string[]> {
    map<string[]> studentNames = {};

    foreach string className in classes.keys() {
        string[] names = [];
        foreach Student student in classes[className] {
            names.push(student.firstName + " " + student.lastName);
        }
        studentNames[className] = names;
    }

    return studentNames;
}

Solution

  • Student[]? is a union type which means the value can be either an array of Student or nil. You can iterate classes[className] in the foreach (and similarly query expression) only if it is a Student[] and is not nil. So you need to narrow the type down/handle the nil scenario.

    For example,

    function getStudentNames(map<Student[]> classes) returns map<string[]> {
        map<string[]> studentNames = {};
    
        foreach string className in classes.keys() {
            string[] names = [];
            if classes[className] is Student[] {
                Student[] students = <Student[]> classes[className];
                foreach Student student in students {
                    names.push(student.firstName + " " + student.lastName);
                }
            }
            
            studentNames[className] = names;
        }
    
        return studentNames;
    }
    

    Simply you can do as follows by using the map function in an array.

    function getStudentNames(map<Student[]> classes) returns map<string[]> {
        map<string[]> studentNames = {};
    
        foreach string className in classes.keys() {
            string[] names = classes[className] is Student[] ? (<Student[]> classes[className]).map(student => student.firstName + " " + student.lastName) : [];
            
            studentNames[className] = names;
        }
    
        return studentNames;
    }