Skip to content

tags: - arrays - Filter - Map - Reduce - Sort - array-operations


Arrays

Arrays are ordered collections of values. They can contain any type of data and provide powerful methods for manipulation and transformation.


Array Creation

Array Literal

numbers = [1, 2, 3, 4, 5];
names = ["Alice", "Bob", "Charlie"];
mixed = [1, "text", true, null, $Now()];

Empty Array

empty = [];

Using $Array Function

// Create empty array
arr = $Array();

// Create from values
arr = $Array(1, 2, 3, 4, 5);

Nested Arrays

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

firstRow = matrix[0]; // [1, 2, 3]
firstElement = matrix[0][0]; // 1

Array Access

Zero-Based Indexing

items = ["first", "second", "third"];

first = items[0]; // "first"
second = items[1]; // "second"
third = items[2]; // "third"

Negative Indices Not Supported

items = [1, 2, 3, 4, 5];

// ERROR: Negative indices not supported
// last = items[-1];

// CORRECT: Calculate index
last = items[items.Length - 1]; // 5

Out of Bounds Access

Returns null:

items = [1, 2, 3];

value = items[10]; // null (index doesn't exist)

Array Length

The .Length property returns the number of elements:

numbers = [1, 2, 3, 4, 5];

count = numbers.Length; // 5

empty = [];
emptyCount = empty.Length; // 0

Modifying Arrays

Adding Elements

.Push() - Add to End

items = [1, 2, 3];
items.Push(4); // [1, 2, 3, 4]
items.Push(5); // [1, 2, 3, 4, 5]

.Insert() - Add at Index

items = [1, 2, 4, 5];
items.Insert(2, 3); // [1, 2, 3, 4, 5]

.AddRange() - Add Multiple

numbers = [1, 2, 3];
moreNumbers = [4, 5, 6];

result = numbers.AddRange(moreNumbers); // [1, 2, 3, 4, 5, 6]

Removing Elements

.Remove() - Remove by Value

items = [1, 2, 3, 2, 4];
items.Remove(2); // [1, 3, 2, 4] (removes first 2)

.RemoveAt() - Remove by Index

items = [1, 2, 3, 4, 5];
items.RemoveAt(2); // [1, 2, 4, 5] (removes index 2)

.Clear() - Remove All

items = [1, 2, 3, 4, 5];
items.Clear(); // []

Updating Elements

items = [1, 2, 3];

// Direct assignment not supported
// items[1] = 20;                       // ERROR

// Use .RemoveAt() then .Insert()
items.RemoveAt(1);
items.Insert(1, 20); // [1, 20, 3]

Array Methods Overview

Arrays have 40+ methods. See Native Functions - Arrays for complete reference.

Filtering and Finding

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// .Filter() - Get all matching elements
evens = numbers.Filter((x) => x % 2 == 0); // [2, 4, 6, 8, 10]

// .Find() - Get first matching element
firstEven = numbers.Find((x) => x % 2 == 0); // 2

// .Any() - Check if any match
hasEvens = numbers.Any((x) => x % 2 == 0); // true

// .All() - Check if all match
allPositive = numbers.All((x) => x > 0); // true

Mapping and Transforming

numbers = [1, 2, 3, 4, 5];

// .Map() - Transform each element
doubled = numbers.Map((x) => x * 2); // [2, 4, 6, 8, 10]

// With index
indexed = numbers.Map((x, i) => x + i); // [1, 3, 5, 7, 9]

Reducing

numbers = [1, 2, 3, 4, 5];

// .ReduceToNum() - Reduce to number
sum = numbers.ReduceToNum((acc, x) => acc + x, 0); // 15

// .Reduce() - Reduce to string
text = numbers.Reduce((acc, x) => acc + $ToString(x), ""); // "12345"

// .ReduceToArr() - Reduce to array
pairs = numbers.ReduceToArr((acc, x) => {
  acc.Push(x * 2);
  return acc;
}, []); // [2, 4, 6, 8, 10]

Sorting

numbers = [5, 2, 8, 1, 9];

// .OrderBy() - Ascending
ascending = numbers.OrderBy((x) => x); // [1, 2, 5, 8, 9]

// .OrderByDescending() - Descending
descending = numbers.OrderByDescending((x) => x); // [9, 8, 5, 2, 1]

// Sort objects
customers = [
  { name: "Charlie", age: 35 },
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
];

byAge = customers.OrderBy((c) => c.age);
byName = customers.OrderBy((c) => c.name);

Taking and Skipping

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// .Take() - Get first N elements
first3 = numbers.Take(3); // [1, 2, 3]

// .Skip() - Skip first N elements
rest = numbers.Skip(3); // [4, 5, 6, 7, 8, 9, 10]

// Combine for pagination
page2 = numbers.Skip(5).Take(5); // [6, 7, 8, 9, 10]

Distinct Values

numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];

unique = numbers.Distinct(); // [1, 2, 3, 4, 5]

Iteration

names = ["Alice", "Bob", "Charlie"];

// .ForEach() - Execute for each element
names.ForEach((name) => $Log(name));

// With index
names.ForEach((name, index) => {
  $Log(index + ": " + name);
});

Working with Objects in Arrays

Array of Objects

customers = [
  { name: "Alice", age: 30, premium: 1200 },
  { name: "Bob", age: 25, premium: 1500 },
  { name: "Charlie", age: 35, premium: 1100 },
];

Filtering Objects

// Get customers with premium > 1200
highPremium = customers.Filter((c) => c.premium > 1200);

// Get active customers
active = customers.Filter((c) => c.isActive);

// Complex conditions
eligible = customers.Filter((c) => c.age >= 18 && c.premium < 2000);

Extracting Properties

// Get all names
names = customers.Map((c) => c.name);
// ["Alice", "Bob", "Charlie"]

// Get all ages
ages = customers.Map((c) => c.age);
// [30, 25, 35]

Transforming Objects

// Create simplified objects
simplified = customers.Map((c) => {
  return {
    name: c.name,
    monthlyPremium: $Round(c.premium / 12, 2),
  };
});

Aggregating Object Data

// Total premiums
totalPremiums = customers.ReduceToNum((acc, c) => acc + c.premium, 0); // 3800

// Average age
totalAge = customers.ReduceToNum((acc, c) => acc + c.age, 0);
avgAge = totalAge / customers.Length; // 30

// Concatenate names
allNames = customers.Reduce((acc, c) => acc + c.name + ", ", ""); // "Alice, Bob, Charlie, "

Sorting Objects

// Sort by age
byAge = customers.OrderBy((c) => c.age);

// Sort by premium (descending)
byPremium = customers.OrderByDescending((c) => c.premium);

// Sort by name
byName = customers.OrderBy((c) => c.name);

Chaining Array Methods

Combine multiple operations:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

result = numbers
  .Filter((x) => x > 3) // [4, 5, 6, 7, 8, 9, 10]
  .Map((x) => x * 2) // [8, 10, 12, 14, 16, 18, 20]
  .Take(3); // [8, 10, 12]

Complex pipeline:

customers = getCustomers();

highValueActive = customers
  .Filter((c) => c.isActive) // Active only
  .Filter((c) => c.premium > 1000) // High premium
  .Map((c) => {
    // Transform
    return {
      name: c.firstName + " " + c.lastName,
      annualPremium: c.premium * 12,
      yearsWithUs: $DifferenceInYears($Today(), c.joinDate),
    };
  })
  .OrderByDescending((c) => c.annualPremium) // Sort by premium
  .Take(10); // Top 10

Common Patterns

Pattern 1: Sum Array

numbers = [1, 2, 3, 4, 5];

// Using reduce
sum = numbers.ReduceToNum((acc, x) => acc + x, 0);

// Using $Sum (if available)
sum = $Sum(numbers);

Pattern 2: Find Maximum

numbers = [5, 2, 8, 1, 9, 3];

// Using reduce
max = numbers.ReduceToNum((acc, x) => (x > acc ? x : acc), numbers[0]);

// Using $Max
max = $Max(numbers);

Pattern 3: Count Matching

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Count even numbers
evenCount = numbers.Filter((x) => x % 2 == 0).Length;

// Or using reduce
evenCount = numbers.ReduceToNum((acc, x) => (x % 2 == 0 ? acc + 1 : acc), 0);

Pattern 4: Group By

customers = getCustomers();

// Separate by age group
young = customers.Filter((c) => c.age < 25);
middle = customers.Filter((c) => c.age >= 25 && c.age < 65);
senior = customers.Filter((c) => c.age >= 65);

Pattern 5: Flatten Nested Arrays

nested = [
  [1, 2],
  [3, 4],
  [5, 6],
];

// Manual flatten
flat = nested.ReduceToArr((acc, arr) => acc.AddRange(arr), []);
// [1, 2, 3, 4, 5, 6]

Pattern 6: Remove Duplicates

numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];

unique = numbers.Distinct(); // [1, 2, 3, 4, 5]

Pattern 7: Pagination

items = getAllItems();
pageSize = 10;
pageNumber = 2; // Zero-based

page = items.Skip(pageNumber * pageSize).Take(pageSize);

Pattern 8: Convert to Object Map

customers = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];

// Create lookup object (manual)
lookup = {};
customers.ForEach((c) => {
  $SetValue(lookup, $ToString(c.id), c);
});

// Now can access by id
customer2 = $GetValue(lookup, "2"); // { "id": 2, "name": "Bob" }

Nested Arrays

Creating Nested Structures

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

departments = [
  {
    name: "Sales",
    employees: [
      { name: "Alice", salary: 50000 },
      { name: "Bob", salary: 55000 },
    ],
  },
  {
    name: "Engineering",
    employees: [
      { name: "Charlie", salary: 80000 },
      { name: "Diana", salary: 85000 },
    ],
  },
];

Accessing Nested Data

// Access matrix element
value = matrix[1][2]; // 6

// Access nested employee
firstDept = departments[0];
firstEmployee = firstDept.employees[0];
salary = firstEmployee.salary; // 50000

// Or combined
salary = departments[0].employees[0].salary; // 50000

Flattening Nested Arrays

departments = [
  {
    name: "Sales",
    employees: [{ name: "Alice" }, { name: "Bob" }],
  },
  {
    name: "Engineering",
    employees: [{ name: "Charlie" }, { name: "Diana" }],
  },
];

// Flatten all employees
allEmployees = departments.ReduceToArr((acc, dept) => {
  return acc.AddRange(dept.employees);
}, []);

// allEmployees = [
//     { "name": "Alice" },
//     { "name": "Bob" },
//     { "name": "Charlie" },
//     { "name": "Diana" }
// ]

Best Practices

1. Use Appropriate Method

// Less ideal: Map when you need filter
result = numbers.Map((x) => (x > 5 ? x : null)).Filter((x) => x != null);

// Better: Just filter
result = numbers.Filter((x) => x > 5);

2. Chain Operations Clearly

// Hard to read
result = customers
  .Filter((c) => c.isActive)
  .Map((c) => c.name)
  .OrderBy((n) => n)
  .Take(10);

// Easier to read
result = customers
  .Filter((c) => c.isActive)
  .Map((c) => c.name)
  .OrderBy((n) => n)
  .Take(10);

3. Check Length Before Access

items = getItems();

// Unsafe
first = items[0];

// Safe
if (items.Length > 0) {
  first = items[0];
}

4. Use .Any() Instead of .Length > 0

// Less clear
if (items.Filter((x) => x.isValid).Length > 0) {
  // ...
}

// Clearer
if (items.Any((x) => x.isValid)) {
  // ...
}

5. Prefer Reduce for Aggregation

// Less ideal: Manual loop
sum = 0;
index = 0;
while (index < numbers.Length) {
  sum += numbers[index];
  index++;
}

// Better: Use reduce
sum = numbers.ReduceToNum((acc, x) => acc + x, 0);

6. Extract Complex Lambdas

// Complex inline lambda
result = items.Map((x) => {
  // 20 lines of complex logic
});

// Better: Extract to function
function processItem(item) {
  // 20 lines of complex logic
}
result = items.Map((item) => processItem(item));

Common Mistakes

Mistake 1: Expecting Negative Indices

items = [1, 2, 3, 4, 5];

// ERROR: Negative indices not supported
// last = items[-1];

// CORRECT
last = items[items.Length - 1];

Mistake 2: Direct Element Assignment

items = [1, 2, 3];

// ERROR: Cannot assign directly
// items[1] = 20;

// CORRECT: Remove and insert
items.RemoveAt(1);
items.Insert(1, 20);

Mistake 3: Forgetting Return in Reduce

numbers = [1, 2, 3, 4, 5];

// ERROR: Forgot to return accumulator
// sum = numbers.ReduceToNum((acc, x) => {
//     acc + x;                                     // Missing return!
// }, 0);

// CORRECT
sum = numbers.ReduceToNum((acc, x) => {
  return acc + x;
}, 0);

// Or use expression body
sum = numbers.ReduceToNum((acc, x) => acc + x, 0);

Mistake 4: Not Handling Empty Arrays

items = [];

// ERROR: Accessing empty array
// first = items[0];                                // null

// CORRECT: Check first
if (items.Length > 0) {
  first = items[0];
}

Mistake 5: Modifying Array During Iteration

// Problematic: Modifying while iterating
items.ForEach((item) => {
  items.Push(item * 2); // Don't do this!
});

// Better: Create new array
doubled = items.Map((item) => item * 2);

Advanced Examples

Example 1: Complex Filtering

policies = getPolicies();

// Find high-value, active policies for senior customers
result = policies
  .Filter((p) => p.isActive)
  .Filter((p) => p.customer.age >= 65)
  .Filter((p) => p.premium > 2000)
  .OrderByDescending((p) => p.premium)
  .Take(20);

Example 2: Statistical Aggregation

function calculateStats(numbers) {
  count = numbers.Length;

  sum = numbers.ReduceToNum((acc, x) => acc + x, 0);
  average = sum / count;

  min = numbers.ReduceToNum((acc, x) => (x < acc ? x : acc), numbers[0]);
  max = numbers.ReduceToNum((acc, x) => (x > acc ? x : acc), numbers[0]);

  aboveAvg = numbers.Filter((x) => x > average).Length;
  belowAvg = numbers.Filter((x) => x < average).Length;

  return {
    count: count,
    sum: $Round(sum, 2),
    average: $Round(average, 2),
    min: min,
    max: max,
    aboveAverage: aboveAvg,
    belowAverage: belowAvg,
  };
}

sales = [1200, 1500, 980, 2100, 1750, 1300];
stats = calculateStats(sales);

Example 3: Data Transformation Pipeline

rawData = getCustomerData();

// Transform and enrich data
processedData = rawData
  .Filter((c) => c.email != null) // Valid email
  .Map((c) => {
    age = $DifferenceInYears($Today(), c.birthDate);

    return {
      customerId: c.id,
      fullName: c.firstName + " " + c.lastName,
      age: age,
      ageGroup: age < 25 ? "young" : age < 65 ? "standard" : "senior",
      email: c.email.ToLower(),
      tenure: $DifferenceInYears($Today(), c.joinDate),
      isHighValue: c.lifetimeValue > 50000,
    };
  })
  .Filter((c) => c.age >= 18) // Adults only
  .OrderByDescending((c) => c.tenure); // Sort by tenure

Example 4: Grouped Aggregation

orders = getOrders();

// Group by status and calculate totals
pending = orders.Filter((o) => o.status == "pending");
completed = orders.Filter((o) => o.status == "completed");
cancelled = orders.Filter((o) => o.status == "cancelled");

report = {
  pending: {
    count: pending.Length,
    total: pending.ReduceToNum((acc, o) => acc + o.amount, 0),
  },
  completed: {
    count: completed.Length,
    total: completed.ReduceToNum((acc, o) => acc + o.amount, 0),
  },
  cancelled: {
    count: cancelled.Length,
    total: cancelled.ReduceToNum((acc, o) => acc + o.amount, 0),
  },
};

Example 5: Nested Array Processing

departments = getDepartments();

// Calculate company-wide salary statistics
allSalaries = departments.ReduceToArr((acc, dept) => {
  salaries = dept.employees.Map((e) => e.salary);
  return acc.AddRange(salaries);
}, []);

avgSalary =
  allSalaries.ReduceToNum((acc, s) => acc + s, 0) / allSalaries.Length;

highEarners = departments
  .Map((dept) => {
    return {
      department: dept.name,
      highEarners: dept.employees
        .Filter((e) => e.salary > avgSalary)
        .OrderByDescending((e) => e.salary),
    };
  })
  .Filter((dept) => dept.highEarners.Length > 0);

Next Steps