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¶
Using $Array Function¶
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:
Array Length¶
The .Length property returns the number of elements:
Modifying Arrays¶
Adding Elements¶
.Push() - Add to End¶
.Insert() - Add at Index¶
.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¶
.RemoveAt() - Remove by Index¶
.Clear() - Remove All¶
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¶
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¶
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¶
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¶
- Explore all array methods: Native Functions - Arrays
- See practical examples: Array Operations
- Learn lambda expressions: Lambda Expressions
- Understand objects in arrays: Objects