Skip to content

Array Operations

This guide demonstrates working with arrays in EverSharp, including filtering, mapping, reducing, sorting, and complex data transformations.

Creating Arrays

Array Literals

// Empty array
empty = [];

// Array of numbers
numbers = [1, 2, 3, 4, 5];

// Array of strings
names = ["Alice", "Bob", "Charlie"];

// Mixed types (not recommended but allowed)
mixed = [1, "hello", true, null];

// Array of objects
policies = [
  { id: 1, premium: 1200, status: "Active" },
  { id: 2, premium: 850, status: "Pending" },
  { id: 3, premium: 1500, status: "Active" },
];

Using $Array Constructor

// Create array from items
arr = $Array(10, 20, 30); // [10, 20, 30]

// Create empty array
empty = $Array(); // []

Accessing Array Elements

By Index

numbers = [10, 20, 30, 40, 50];

first = numbers[0]; // 10
second = numbers[1]; // 20
last = numbers[4]; // 50

// Get array length
count = numbers.Length; // 5

Filtering Arrays

Filter Method

The .Filter() method selects elements that match a condition:

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

// Get even numbers
evens = numbers.Filter((n) => n % 2 == 0);
// Result: [2, 4, 6, 8, 10]

// Get numbers greater than 5
large = numbers.Filter((n) => n > 5);
// Result: [6, 7, 8, 9, 10]

Filtering Objects

policies = [
  { id: 1, premium: 1200, status: "Active" },
  { id: 2, premium: 850, status: "Lapsed" },
  { id: 3, premium: 1500, status: "Active" },
  { id: 4, premium: 950, status: "Pending" },
];

// Get only active policies
active = policies.Filter((p) => p.status == "Active");
// Result: [{ id: 1, ... }, { id: 3, ... }]

// Get high-value policies (premium >= 1000)
highValue = policies.Filter((p) => p.premium >= 1000);
// Result: [{ id: 1, ... }, { id: 3, ... }]

// Multiple conditions
activeHighValue = policies.Filter(
  (p) => p.status == "Active" && p.premium >= 1000
);
// Result: [{ id: 1, ... }, { id: 3, ... }]

Finding Elements

Find Method

Find the first element matching a condition:

policies = [
  { id: 1, premium: 1200 },
  { id: 2, premium: 850 },
  { id: 3, premium: 1500 },
];

// Find policy with id = 2
policy = policies.Find((p) => p.id == 2);
// Result: { id: 2, premium: 850 }

// Find first policy with premium > 1000
expensive = policies.Find((p) => p.premium > 1000);
// Result: { id: 1, premium: 1200 }

Any and All Methods

Check if any or all elements match:

numbers = [2, 4, 6, 8, 10];

// Check if any number is greater than 5
hasLarge = numbers.Any((n) => n > 5); // true

// Check if all numbers are even
allEven = numbers.All((n) => n % 2 == 0); // true

// Check if all numbers are greater than 5
allLarge = numbers.All((n) => n > 5); // false

Transforming Arrays

Map Method

Transform each element:

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

// Square each number
squares = numbers.Map((n) => n * n);
// Result: [1, 4, 9, 16, 25]

// Double each number
doubled = numbers.Map((n) => n * 2);
// Result: [2, 4, 6, 8, 10]

Mapping Objects

policies = [
  { id: 1, premium: 1200, status: "Active" },
  { id: 2, premium: 850, status: "Lapsed" },
  { id: 3, premium: 1500, status: "Active" },
];

// Extract just the premiums
premiums = policies.Map((p) => p.premium);
// Result: [1200, 850, 1500]

// Create summary objects
summaries = policies.Map((p) => {
  return {
    policyId: p.id,
    amount: p.premium,
    isActive: p.status == "Active",
  };
});
// Result: [{ policyId: 1, amount: 1200, isActive: true }, ...]

Map with Index

The second parameter is the index:

items = ["A", "B", "C"];

// Add index to each item
numbered = items.Map((item, index) => {
  return $ToString(index + 1) + ". " + item;
});
// Result: ["1. A", "2. B", "3. C"]

Reducing Arrays

Sum Numbers

numbers = [10, 20, 30, 40, 50];

// Sum all numbers
total = numbers.ReduceToNum((sum, n) => sum + n, 0);
// Result: 150

Calculate Average

values = [85, 90, 78, 92, 88];

total = values.ReduceToNum((sum, n) => sum + n, 0);
average = total / values.Length;
// Result: 86.6

Find Maximum

numbers = [45, 12, 89, 23, 67];

maximum = numbers.ReduceToNum((max, n) => {
  if (n > max) {
    return n;
  } else {
    return max;
  }
}, numbers[0]);
// Result: 89

Reduce to Object

policies = [
  { status: "Active", premium: 1200 },
  { status: "Active", premium: 850 },
  { status: "Lapsed", premium: 1500 },
];

// Count by status
summary = policies.Reduce(
  (acc, p) => {
    if (p.status == "Active") {
      acc.activeCount = acc.activeCount + 1;
      acc.activePremium = acc.activePremium + p.premium;
    } else {
      acc.lapsedCount = acc.lapsedCount + 1;
      acc.lapsedPremium = acc.lapsedPremium + p.premium;
    }
    return acc;
  },
  {
    activeCount: 0,
    activePremium: 0,
    lapsedCount: 0,
    lapsedPremium: 0,
  }
);
// Result: { activeCount: 2, activePremium: 2050, lapsedCount: 1, lapsedPremium: 1500 }

Sorting Arrays

Sort Numbers

numbers = [45, 12, 89, 23, 67];

// Sort ascending
ascending = numbers.OrderBy((n) => n);
// Result: [12, 23, 45, 67, 89]

// Sort descending
descending = numbers.OrderByDescending((n) => n);
// Result: [89, 67, 45, 23, 12]

Sort Objects

policies = [
  { id: 3, premium: 1500 },
  { id: 1, premium: 850 },
  { id: 2, premium: 1200 },
];

// Sort by premium (ascending)
byPremium = policies.OrderBy((p) => p.premium);
// Result: [{ id: 1, premium: 850 }, { id: 2, premium: 1200 }, { id: 3, premium: 1500 }]

// Sort by id (ascending)
byId = policies.OrderBy((p) => p.id);
// Result: [{ id: 1, ... }, { id: 2, ... }, { id: 3, ... }]

// Sort by premium (descending)
byPremiumDesc = policies.OrderByDescending((p) => p.premium);
// Result: [{ id: 3, premium: 1500 }, { id: 2, premium: 1200 }, { id: 1, premium: 850 }]

Slicing and Pagination

Take and Skip

numbers = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];

// Take first 3
first3 = numbers.Take(3);
// Result: [10, 20, 30]

// Skip first 3
rest = numbers.Skip(3);
// Result: [40, 50, 60, 70, 80, 90, 100]

// Pagination: Page 2 with 3 items per page
page = 2;
pageSize = 3;
pageData = numbers.Skip((page - 1) * pageSize).Take(pageSize);
// Result: [40, 50, 60]

Slice Method

numbers = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];

// Get elements from index 2 to 5 (exclusive)
subset = numbers.Slice(2, 5);
// Result: [30, 40, 50]

// Get from index 5 to end
fromFive = numbers.Slice(5, numbers.Length);
// Result: [60, 70, 80, 90, 100]

Modifying Arrays

Adding Elements

numbers = [10, 20, 30];

// Add to end
numbers.Push(40);
// numbers is now: [10, 20, 30, 40]

// Insert at specific position
numbers.Insert(1, 15);
// numbers is now: [10, 15, 20, 30, 40]

// Add multiple elements
numbers.AddRange([50, 60, 70]);
// numbers is now: [10, 15, 20, 30, 40, 50, 60, 70]

Removing Elements

numbers = [10, 20, 30, 40, 50];

// Remove by value
numbers.Remove(30);
// numbers is now: [10, 20, 40, 50]

// Remove by index
numbers.RemoveAt(1);
// numbers is now: [10, 40, 50]

// Clear all elements
numbers.Clear();
// numbers is now: []

Array Utilities

Distinct Values

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

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

Reverse Array

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

reversed = numbers.Reverse();
// Result: [5, 4, 3, 2, 1]

Join Array

words = ["Hello", "World", "!"];

sentence = words.Join(" ");
// Result: "Hello World !"

// Join with comma
csv = words.Join(",");
// Result: "Hello,World,!"

IndexOf

numbers = [10, 20, 30, 40, 50];

index = numbers.IndexOf(30);
// Result: 2

// Not found returns -1
notFound = numbers.IndexOf(99);
// Result: -1

Practical Examples

Example 1: Calculate Total Premium

policies = [
  { id: 1, premium: 1200 },
  { id: 2, premium: 850 },
  { id: 3, premium: 1500 },
  { id: 4, premium: 950 },
];

totalPremium = policies
  .Map((p) => p.premium)
  .ReduceToNum((sum, p) => sum + p, 0);
// Result: 4500

Example 2: Filter and Sort

policies = [
  { id: 3, premium: 1500, status: "Active" },
  { id: 1, premium: 850, status: "Lapsed" },
  { id: 4, premium: 1200, status: "Active" },
  { id: 2, premium: 950, status: "Active" },
];

// Get active policies sorted by premium descending
activeSorted = policies
  .Filter((p) => p.status == "Active")
  .OrderByDescending((p) => p.premium);
// Result: [{ id: 3, premium: 1500 }, { id: 4, premium: 1200 }, { id: 2, premium: 950 }]

Example 3: Group and Count

claims = [
  { type: "Auto", amount: 1500 },
  { type: "Home", amount: 3000 },
  { type: "Auto", amount: 2500 },
  { type: "Life", amount: 5000 },
  { type: "Auto", amount: 1200 },
];

// Count by type
summary = claims.Reduce((acc, claim) => {
  type = claim.type;

  // Find existing type in accumulator
  existing = acc.Find((item) => item.type == type);

  if (existing == null) {
    // Add new type
    acc.Push({
      type: type,
      count: 1,
      total: claim.amount,
    });
  } else {
    // Update existing type
    existing.count = existing.count + 1;
    existing.total = existing.total + claim.amount;
  }

  return acc;
}, []);

// Result: [
//   { type: "Auto", count: 3, total: 5200 },
//   { type: "Home", count: 1, total: 3000 },
//   { type: "Life", count: 1, total: 5000 }
// ]

Example 4: Top N Items

policies = [
  { id: 1, premium: 1200 },
  { id: 2, premium: 850 },
  { id: 3, premium: 1500 },
  { id: 4, premium: 950 },
  { id: 5, premium: 1800 },
];

// Get top 3 policies by premium
top3 = policies.OrderByDescending((p) => p.premium).Take(3);
// Result: [{ id: 5, premium: 1800 }, { id: 3, premium: 1500 }, { id: 1, premium: 1200 }]

Example 5: Calculate Statistics

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

  if (count == 0) {
    return null;
  }

  // Sum
  sum = numbers.ReduceToNum((total, n) => total + n, 0);

  // Average
  avg = sum / count;

  // Min and Max
  min = numbers.ReduceToNum((m, n) => {
    if (n < m) {
      return n;
    } else {
      return m;
    }
  }, numbers[0]);

  max = numbers.ReduceToNum((m, n) => {
    if (n > m) {
      return n;
    } else {
      return m;
    }
  }, numbers[0]);

  return {
    count: count,
    sum: sum,
    average: avg,
    min: min,
    max: max,
  };
};

premiums = [1200, 850, 1500, 950, 1800];
stats = calculateStats(premiums);

// Result: {
//   count: 5,
//   sum: 6300,
//   average: 1260,
//   min: 850,
//   max: 1800
// }

Example 6: Flatten Nested Arrays

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

// Flatten to single array
flattened = nested.ReduceToArr((acc, arr) => {
  // Add all elements from arr to acc
  arr.ForEach((n) => {
    acc.Push(n);
  });
  return acc;
}, []);
// Result: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Example 7: Remove Duplicates by Property

customers = [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob", email: "bob@example.com" },
  { id: 3, name: "Alice", email: "alice@example.com" },
  { id: 4, name: "Charlie", email: "charlie@example.com" },
];

// Remove duplicates by email
uniqueByEmail = customers.Reduce((acc, customer) => {
  // Check if email already exists
  exists = acc.Any((c) => c.email == customer.email);

  if (!exists) {
    acc.Push(customer);
  }

  return acc;
}, []);

// Result: [
//   { id: 1, name: "Alice", email: "alice@example.com" },
//   { id: 2, name: "Bob", email: "bob@example.com" },
//   { id: 4, name: "Charlie", email: "charlie@example.com" }
// ]

Example 8: Partition Array

Split array into groups based on condition:

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

partition = numbers.Reduce(
  (acc, n) => {
    if (n % 2 == 0) {
      acc.evens.Push(n);
    } else {
      acc.odds.Push(n);
    }
    return acc;
  },
  { evens: [], odds: [] }
);

// Result: {
//   evens: [2, 4, 6, 8, 10],
//   odds: [1, 3, 5, 7, 9]
// }

Example 9: Search and Replace

policies = [
  { id: 1, status: "Active" },
  { id: 2, status: "Pending" },
  { id: 3, status: "Active" },
];

// Update status of policy with id = 2
updated = policies.Map((p) => {
  if (p.id == 2) {
    // Create new object with updated status
    return {
      id: p.id,
      status: "Active",
    };
  } else {
    return p;
  }
});

// Result: [
//   { id: 1, status: "Active" },
//   { id: 2, status: "Active" },   // Updated
//   { id: 3, status: "Active" }
// ]

Example 10: Complex Chaining

transactions = [
  { date: $ToDate("2024-01-15"), amount: 1200, type: "Premium" },
  { date: $ToDate("2024-02-20"), amount: -500, type: "Claim" },
  { date: $ToDate("2024-03-10"), amount: 1200, type: "Premium" },
  { date: $ToDate("2024-04-05"), amount: -750, type: "Claim" },
  { date: $ToDate("2024-05-15"), amount: 1200, type: "Premium" },
];

// Calculate total premiums for current year
currentYear = $Year($Today());

totalPremiums = transactions
  .Filter((t) => t.type == "Premium")
  .Filter((t) => $Year(t.date) == currentYear)
  .Map((t) => t.amount)
  .ReduceToNum((sum, amt) => sum + amt, 0);

// Result: 3600 (sum of all Premium amounts)

Common Patterns

Check if Array is Empty

items = [];

isEmpty = items.Length == 0; // true

Safe Array Access

getItemSafe = function (array, index) {
  if (index >= 0 && index < array.Length) {
    return array[index];
  } else {
    return null;
  }
};

numbers = [10, 20, 30];
item = getItemSafe(numbers, 5); // null (index out of range)

Convert to Lookup Object

items = [
  { id: "A", value: 10 },
  { id: "B", value: 20 },
  { id: "C", value: 30 },
];

// Note: EverSharp doesn't have direct object key manipulation,
// so we'll use Find for lookup instead
lookup = function (arr, id) {
  item = arr.Find((x) => x.id == id);
  if (item != null) {
    return item.value;
  } else {
    return null;
  }
};

value = lookup(items, "B"); // 20

Best Practices

Chain Operations for Clarity

// Good: clear chain of operations
result = items
  .Filter((x) => x.active)
  .OrderBy((x) => x.priority)
  .Take(10);

// Less clear: nested function calls
result = items
  .Filter((x) => x.active)
  .OrderBy((x) => x.priority)
  .Take(10);

Use Descriptive Lambda Parameters

// Good: descriptive name
customers.Filter((customer) => customer.age >= 18);

// Less clear: single letter
customers.Filter((c) => c.age >= 18);

Avoid Modifying Arrays During Iteration

// Don't modify array while iterating
// Instead, create a new array with the changes

// Wrong:
// arr.ForEach((item) => {
//     arr.Remove(item);  // Modifying during iteration
// });

// Correct: use Filter to create new array
newArr = arr.Filter((item) => /* condition to keep */);

Next Steps

See Also