For instance, loop counters are a common pattern for mutable variables and are built into most iterating commands. For example, you can get both each item and the index of each item using [`each`](/commands/docs/each.md) with [`enumerate`](/commands/docs/enumerate.md):
```nu
ls | enumerate | each { |elt| $"Item #($elt.index) is size ($elt.item.size)" }
# => ╭───┬───────────────────────────╮
# => │ 0 │ Item #0 is size 812 B │
# => │ 1 │ Item #1 is size 3.4 KiB │
# => │ 2 │ Item #2 is size 11.0 KiB │
# => │ 3 │ ... │
# => │ 4 │ Item #18 is size 17.8 KiB │
# => │ 5 │ Item #19 is size 482 B │
# => │ 6 │ Item #20 is size 4.0 KiB │
# => ╰───┴───────────────────────────╯
```
You can also use the [`reduce`](/commands/docs/reduce.md) command to work in the same way you might mutate a variable in a loop. For example, if you wanted to find the largest string in a list of strings, you might do:
```nu
[one, two, three, four, five, six] | reduce {|current_item, max|
if ($current_item | str length) > ($max | str length) {
$current_item
} else {
$max
}
}
three
```
While `reduce` processes lists, the [`generate`](/commands/docs/generate.md) command can be used with arbitrary sources such as external REST APIs, also without requiring mutable variables. Here's an example that retrieves local weather data every hour and generates a continuous list from that data. The `each` command can be used to consume each new list item as it becomes available.
```nu
generate khot {|weather_station|
let res = try {
http get -ef $'https://api.weather.gov/stations/($weather_station)/observations/latest'
} catch {
null
}
sleep 1hr
match $res {
null => {
next: $weather_station
}
_ => {
out: ($res.body? | default '' | from json)
next: $weather_station
}
}
}
| each {|weather_report|
{
time: ($weather_report.properties.timestamp | into datetime)
temp: $weather_report.properties.temperature.value
}
}
```
### Performance Considerations
Using [filter commands](/commands/categories/filters.html) with immutable variables is often far more performant than mutable variables with traditional flow-control statements such as `for` and `while`. For example:
- Using a `for` statement to create a list of 50,000 random numbers:
```nu
timeit {
mut randoms = []
for _ in 1..50_000 {
$randoms = ($randoms | append (random int))
}
}
```
Result: 1min 4sec 191ms 135µs 90ns
- Using `each` to do the same:
```nu
timeit {
let randoms = (1..50_000 | each {random int})
}
```
Result: 19ms 314µs 205ns
- Using `each` with 10,000,000 iterations:
```nu
timeit {
let randoms = (1..10_000_000 | each {random int})
}
```
Result: 4sec 233ms 865µs 238ns
As with many filters, the `each` statement also streams its results, meaning the next stage of the pipeline can continue processing without waiting for the results to be collected into a variable.
For tasks which can be optimized by parallelization, as mentioned above, `par-each` can have even more drastic performance gains.
## Variable Names
Variable names in Nushell come with a few restrictions as to what characters they can contain. In particular, they cannot contain these characters:
```text
. [ ( { + - * ^ / = ! < > & |
```
It is common for some scripts to declare variables that start with `$`. This is allowed, and it is equivalent to the `$` not being there at all.
```nu
let $var = 42
# identical to `let var = 42`
```