Transformations
Change data as it flows through your pipeline.
map()
Transform each item:
import { enumerate } from "jsr:@j50n/proc@0.23.3";
const doubled = await enumerate([1, 2, 3])
.map(n => n * 2)
.collect();
// [2, 4, 6]
With Async Functions
const results = await enumerate(urls)
.map(async (url) => {
const response = await fetch(url);
return response.json();
})
.collect();
Type Transformations
const strings = await enumerate([1, 2, 3])
.map(n => n.toString())
.collect();
// ["1", "2", "3"]
Complex Transformations
const processed = await enumerate(rawData)
.map(item => ({
id: item.id,
name: item.name.toUpperCase(),
value: parseFloat(item.value),
timestamp: new Date(item.timestamp)
}))
.collect();
flatMap()
Map and flatten in one step:
const words = await enumerate(["hello world", "foo bar"])
.flatMap(line => line.split(" "))
.collect();
// ["hello", "world", "foo", "bar"]
Expanding Items
const expanded = await enumerate([1, 2, 3])
.flatMap(n => [n, n * 10])
.collect();
// [1, 10, 2, 20, 3, 30]
Filtering While Mapping
const valid = await enumerate(data)
.flatMap(item => {
if (item.valid) {
return [item.value];
}
return []; // Skip invalid items
})
.collect();
filter()
Keep only matching items:
const evens = await enumerate([1, 2, 3, 4, 5])
.filter(n => n % 2 === 0)
.collect();
// [2, 4]
Complex Predicates
const active = await enumerate(users)
.filter(user =>
user.active &&
user.lastLogin > cutoffDate &&
user.role !== "guest"
)
.collect();
With Type Guards
const numbers = await enumerate(mixed)
.filter((item): item is number => typeof item === "number")
.collect();
transform()
Apply a TransformStream:
import { read } from "jsr:@j50n/proc@0.23.3";
const decompressed = await read("file.gz")
.transform(new DecompressionStream("gzip"))
.lines
.collect();
Custom Transform
const transformed = await enumerate(data)
.transform(new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
}
}))
.collect();
Chaining Transformations
Combine multiple transformations:
const result = await enumerate(data)
.map(item => item.trim())
.filter(item => item.length > 0)
.map(item => item.toUpperCase())
.filter(item => item.startsWith("A"))
.collect();
Real-World Examples
Parse CSV
const data = await read("data.csv")
.lines
.drop(1) // Skip header
.map(line => line.split(","))
.map(([name, age, city]) => ({
name,
age: parseInt(age),
city
}))
.filter(row => row.age >= 18)
.collect();
Extract URLs
const urls = await read("page.html")
.lines
.flatMap(line => {
const matches = line.match(/https?:\/\/[^\s"']+/g);
return matches || [];
})
.collect();
Clean Data
const cleaned = await enumerate(rawData)
.map(item => item.trim())
.filter(item => item.length > 0)
.map(item => item.toLowerCase())
.filter(item => !item.startsWith("#"))
.collect();
Transform JSON Lines
const objects = await read("data.jsonl")
.lines
.map(line => JSON.parse(line))
.filter(obj => obj.status === "active")
.map(obj => ({
id: obj.id,
name: obj.name,
value: obj.value * 1.1 // Apply 10% increase
}))
.collect();
Performance Tips
Lazy Evaluation
Transformations don't run until you consume:
// Nothing happens yet
const pipeline = enumerate(data)
.map(expensive)
.filter(predicate);
// Now it runs
const result = await pipeline.collect();
Early Filtering
Filter before expensive operations:
// ✅ Filter first
const result = await enumerate(data)
.filter(cheap) // Fast filter
.map(expensive) // Expensive operation
.collect();
// ❌ Map first
const result = await enumerate(data)
.map(expensive) // Runs on everything
.filter(cheap) // Then filters
.collect();
Use take() to Limit
// Stop after 10 matches
const first10 = await enumerate(huge)
.filter(predicate)
.take(10)
.collect();
Common Patterns
Normalize Data
const normalized = await enumerate(data)
.map(item => ({
...item,
name: item.name.trim().toLowerCase(),
email: item.email.toLowerCase(),
phone: item.phone.replace(/\D/g, "")
}))
.collect();
Extract Fields
const names = await enumerate(users)
.map(user => user.name)
.collect();
Conditional Transform
const processed = await enumerate(items)
.map(item => {
if (item.type === "A") {
return processTypeA(item);
} else {
return processTypeB(item);
}
})
.collect();
Batch Transform
const batched = await enumerate(items)
.map((item, i) => ({
...item,
batch: Math.floor(i / 100)
}))
.collect();
Error Handling
Errors in transformations propagate:
try {
await enumerate(data)
.map(item => {
if (!item.valid) {
throw new Error(`Invalid item: ${item.id}`);
}
return item.value;
})
.collect();
} catch (error) {
console.error(`Transform failed: ${error.message}`);
}
Next Steps
- Aggregations - Combine items into single values
- Array-Like Methods - All available methods
- Concurrent Processing - Transform in parallel