# Iterable Operators

Iterable operators allow you to work with collections of data such as lists and arrays. These operators help you access, filter, and manipulate elements within your data structures.

***

## Available Operators

### contains()

Checks if a collection contains a specific element.

**Syntax:**

```
${contains(collection, element)}
```

**Parameters:**

* `collection` - The list or array to search in
* `element` - The value to search for

**Returns:** `true` if the element exists in the collection, `false` otherwise

**Examples:**

```javascript
// Check if a list contains a value
${contains(["apple", "banana", "orange"], "banana")}
// Returns: true

${contains([1, 2, 3, 4, 5], 6)}
// Returns: false

// Check if user's tags include "premium"
${contains(user.tags, "premium")}

// Conditional based on contains
${if(contains(selectedItems, currentItem.id), "Selected", "Not Selected")}
```

**Use Cases:**

* Verify if an item is in a selection
* Check if a user has a specific permission or tag
* Validate if a value exists before processing
* Implement toggle functionality (add/remove from list)

***

### elementAt()

Returns the element at a specific index in a collection.

**Syntax:**

```
${elementAt(collection, index)}
```

**Parameters:**

* `collection` - The list or array
* `index` - Zero-based index position (0 for first element, 1 for second, etc.)

**Returns:** The element at the specified index, or `null` if index is out of bounds

**Examples:**

```javascript
// Get the first element
${elementAt(["apple", "banana", "orange"], 0)}
// Returns: "apple"

// Get the third element
${elementAt([10, 20, 30, 40], 2)}
// Returns: 30

// Get element by variable index
${elementAt(products, selectedIndex)}

// Use in expressions
${concat("Selected: ", elementAt(items, currentIndex))}
```

**Use Cases:**

* Access specific items by position
* Get items based on calculated indices
* Retrieve elements when index comes from user input or state
* Alternative to bracket notation `myList[index]`

***

### firstElement()

Returns the first element of a collection.

**Syntax:**

```
${firstElement(collection)}
```

**Parameters:**

* `collection` - The list or array

**Returns:** The first element, or `null` if the collection is empty

**Examples:**

```javascript
// Get first item
${firstElement(["apple", "banana", "orange"])}
// Returns: "apple"

${firstElement([1, 2, 3, 4, 5])}
// Returns: 1

// Display first product name
${firstElement(products).name}

// With fallback for empty list
${if(gt(length(items), 0), firstElement(items), "No items available")}
```

**Use Cases:**

* Show the most recent item (if list is sorted by date)
* Get the top result from search or filter
* Display featured or highlighted item
* Quick access to first element without indexing

***

### lastElement()

Returns the last element of a collection.

**Syntax:**

```
${lastElement(collection)}
```

**Parameters:**

* `collection` - The list or array

**Returns:** The last element, or `null` if the collection is empty

**Examples:**

```javascript
// Get last item
${lastElement(["apple", "banana", "orange"])}
// Returns: "orange"

${lastElement([1, 2, 3, 4, 5])}
// Returns: 5

// Display last message
${lastElement(messages).text}

// Show latest timestamp
${lastElement(history).timestamp}
```

**Use Cases:**

* Show the most recent item (if appending to end)
* Display the final element without calculating index
* Access last page in pagination
* Get the latest entry in chronological data

***

### skip()

Returns a new collection that skips the first N elements.

**Syntax:**

```
${skip(collection, count)}
```

**Parameters:**

* `collection` - The list or array
* `count` - Number of elements to skip from the beginning

**Returns:** A new collection with the first `count` elements removed

**Examples:**

```javascript
// Skip first 2 elements
${skip(["a", "b", "c", "d", "e"], 2)}
// Returns: ["c", "d", "e"]

${skip([1, 2, 3, 4, 5], 3)}
// Returns: [4, 5]

// Pagination: Skip to page 2 (skip first 10 items)
${skip(allItems, 10)}

// Combined with take for pagination
${take(skip(products, mul(diff(currentPage, 1), itemsPerPage)), itemsPerPage)}
```

**Use Cases:**

* Implement pagination (skip previous pages)
* Remove header rows from data
* Start displaying from a certain position
* Offset-based data loading

***

### take()

Returns a new collection containing only the first N elements.

**Syntax:**

```
${take(collection, count)}
```

**Parameters:**

* `collection` - The list or array
* `count` - Number of elements to take from the beginning

**Returns:** A new collection with only the first `count` elements

**Examples:**

```javascript
// Take first 3 elements
${take(["a", "b", "c", "d", "e"], 3)}
// Returns: ["a", "b", "c"]

${take([1, 2, 3, 4, 5], 2)}
// Returns: [1, 2]

// Show only top 5 items
${take(products, 5)}

// Limit display to 10 results
ListView:
  Data Source: ${take(searchResults, 10)}
```

**Use Cases:**

* Limit number of displayed items
* Show "top N" results
* Preview or teaser lists (e.g., "Top 5 Products")
* Implement "Show More" functionality

***

### reversed()

Returns a new collection with elements in reverse order.

**Syntax:**

```
${reversed(collection)}
```

**Parameters:**

* `collection` - The list or array to reverse

**Returns:** A new collection with elements in opposite order

**Examples:**

```javascript
// Reverse a list
${reversed(["a", "b", "c", "d"])}
// Returns: ["d", "c", "b", "a"]

${reversed([1, 2, 3, 4, 5])}
// Returns: [5, 4, 3, 2, 1]

// Show messages in reverse chronological order
ListView:
  Data Source: ${reversed(messages)}

// Display countdown
${reversed(numbers)}
```

**Use Cases:**

* Show newest items first (reverse chronological order)
* Display data in descending order
* Create countdown or reverse sequences
* Reverse user selections

***

## Combining Operators

You can chain multiple iterable operators together for powerful data manipulation:

### Pagination Example

```javascript
// Show items 11-20 (page 2, 10 items per page)
${take(skip(allItems, 10), 10)}

// Dynamic pagination
Variable: currentPage = 2
Variable: itemsPerPage = 10

ListView:
  Data Source: ${take(skip(products, mul(diff(currentPage, 1), itemsPerPage)), itemsPerPage)}
```

### Limited Reversed List

```javascript
// Show last 5 items in reverse order
${take(reversed(items), 5)}

// Show 3 most recent messages
${take(reversed(messages), 3)}
```

### Skip and Check

```javascript
// Get all items except first one
${skip(items, 1)}

// Check if skipped list contains something
${contains(skip(tags, 2), "featured")}
```

### Conditional Access

```javascript
// Get first item if exists
${if(gt(items.length, 0), firstElement(items), "No items")}

// Get last element safely
${if(gt(length(products), 0), lastElement(products), defaultProduct)}
```

***

## Common Patterns

### Empty List Handling

```javascript
Conditional Builder:
  Condition: ${gt(items.length, 0)}
  
  True Child:
    Text: ${firstElement(items).name}
  
  False Child:
    Text: "No items available"
```

### Show Limited Preview

```javascript
// Show first 3 items with "View All" option
Column:
  Children:
    ListView:
      Data Source: ${take(products, 3)}
    
    Button:
      Text: "View All"
      Visible: ${gt(products.length, 3)}
```

### Pagination Controls

```javascript
Variable: currentPage (Number) = 1
Variable: pageSize (Number) = 10

ListView:
  Data Source: ${take(skip(items, mul(diff(currentPage, 1), pageSize)), pageSize)}

Button (Next):
  Enabled: ${lt(mul(currentPage, pageSize), items.length)}
  onClick: Set State: currentPage = ${sum(currentPage, 1)}

Button (Previous):
  Enabled: ${gt(currentPage, 1)}
  onClick: Set State: currentPage = ${diff(currentPage, 1)}
```

### Checking Selection State

```javascript
// Toggle selection
Button:
  Text: ${if(contains(selectedItems, item.id), "Deselect", "Select")}
  Background: ${if(contains(selectedItems, item.id), "blue", "gray")}
```

### Accessing Specific Elements

```javascript
// Safe access with fallback
Text: ${if(isNotNull(elementAt(items, index)), elementAt(items, index), "Item not found")}

// Display range
Text: ${concat("Showing items ", sum(elementAt(items, 0).id, 1), " to ", lastElement(items).id)}
```

***

## Best Practices

* **Check length before accessing:** Always verify the collection has elements before using `firstElement()`, `lastElement()`, or `elementAt()`
* **Use appropriate operators:** Choose `firstElement()` over `elementAt(myList, 0)` for clarity
* **Combine for pagination:** Use `skip()` and `take()` together for efficient pagination
* **Cache results:** If using the same operation multiple times, consider storing the result in a variable
* **Handle null cases:** Use `or()` or conditional `if()` to provide fallbacks when elements might not exist
* **Mind performance:** While operations are efficient, avoid deeply nested chains in large lists displayed in UI

***

## Related Documentation

* [List Variable](https://docs.digia.tech/logic-and-interaction/adding-logic/broken-reference) - Working with list data
* [JSON Operators](https://docs.digia.tech/logic-and-interaction/adding-logic/json-operators) - Working with JSON objects
* [Logical Operators](https://docs.digia.tech/logic-and-interaction/adding-logic/logical-operators) - Conditional logic
* [Math Operators](https://docs.digia.tech/logic-and-interaction/adding-logic/math-operators) - Mathematical operations for indices and counts
* [ListView](https://docs.digia.tech/logic-and-interaction/adding-logic/broken-reference) - Displaying lists in UI
* [GridView](https://docs.digia.tech/logic-and-interaction/adding-logic/broken-reference) - Displaying grids in UI
