Lodash Collections & Arrays — Complete Data Transformation Guide
Lodash collection and array methods transform, search, group, and filter data in one call, working uniformly on arrays and objects without manual loops.
What You’ll Learn
- Collection iteration:
_.forEach,_.map,_.filter,_.reduce,_.reduceRight - Searching:
_.find,_.findLast,_.includes,_.some,_.every - Grouping and aggregation:
_.groupBy,_.keyBy,_.countBy - Array operations:
_.chunk,_.compact,_.uniq,_.union,_.intersection,_.difference - Flattening nested arrays:
_.flatten,_.flattenDeep - Sorting:
_.sortBy,_.orderBy
Why Collections & Arrays Matter
Think of data as items in a filing cabinet. Arrays are like numbered lists (item 1, item 2, item 3) and objects are like labeled folders (name: Alice, role: admin). Lodash lets you work with both using the same syntax and functions.
In Durga Antivirus Pro, file scan results arrive as arrays of threat objects. Before analysis, these arrays must be filtered (remove non-malicious files), sorted (by threat severity), grouped (by file type), and deduplicated (same signature can’t appear twice). Lodash collection methods handle this pipeline in a few lines instead of dozens.
Learning Path
flowchart LR
A["Lodash<br/>Getting Started"] --> B["Collections<br/>& Arrays"]
B --> C["Objects &<br/>Functions"]
B --> D["Real Project:<br/>Data Pipeline"]
C --> E["Utilities &<br/>Performance"]
style B fill:#38bdf8,color:#0f172a,stroke:#38bdf8,stroke-width:2px
style D fill:#22c55e,color:#0f172a
Collection Iteration
The key difference between Lodash collection methods and native JavaScript array methods: Lodash works on both arrays and objects. Native Array.prototype.map only works on arrays.
_.forEach — Visit Every Item
Like reading every card in a filing cabinet drawer. Returns the collection so you can chain.
import forEach from 'lodash/forEach';
// Arrays — same as native forEach
forEach([1, 2, 3], (value, index) => {
console.log(index, value);
});
// 0 1
// 1 2
// 2 3
// Objects — iterates over own properties
forEach({ a: 1, b: 2 }, (value, key) => {
console.log(key, value);
});
// 'a' 1
// 'b' 2
Why bother with _.forEach instead of for...in? _.forEach only iterates over own enumerable properties — it skips prototype-chain properties that for...in would include. This prevents bugs where inherited methods accidentally show up in your iteration.
_.map — Transform Every Item
Think of _.map as a factory conveyor belt: each item goes in, gets transformed by a function, and comes out the other end as a new item.
import map from 'lodash/map';
// Double every number
map([1, 2, 3], n => n * 2);
// [2, 4, 6]
// Works on objects too!
map({ a: 2, b: 4, c: 6 }, (value, key) => `${key}:${value}`);
// ['a:2', 'b:4', 'c:6']
The property shorthand is one of those small features that saves a ton of typing:
const users = [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Charlie' }];
// Without shorthand:
map(users, user => user.name);
// ['Alice', 'Bob', 'Charlie']
// With shorthand — just pass the property name as a string:
map(users, 'name');
// ['Alice', 'Bob', 'Charlie']
_.filter and _.reject — Keep or Remove Items
_.filter keeps items where the predicate returns truthy. _.reject does the opposite — it keeps items where the predicate returns falsy.
Think of _.filter as a bouncer at a club checking IDs. Only those who pass the check get in.
import filter from 'lodash/filter';
import reject from 'lodash/reject';
const numbers = [1, 2, 3, 4, 5, 6];
filter(numbers, n => n % 2 === 0);
// [2, 4, 6]
reject(numbers, n => n % 2 === 0);
// [1, 3, 5]
The matches shorthand is extremely useful for filtering arrays of objects:
const inventory = [
{ item: 'apple', qty: 10 },
{ item: 'banana', qty: 0 },
{ item: 'orange', qty: 5 },
];
// Find items with qty === 0 — like finding out-of-stock products
filter(inventory, { qty: 0 });
// [{ item: 'banana', qty: 0 }]
_.reduce — Combine Into a Single Value
_.reduce is like folding a stack of papers into one envelope. You start with an accumulator, visit each item, and combine them.
import reduce from 'lodash/reduce';
// Sum all numbers — classic example
reduce([1, 2, 3], (sum, n) => sum + n, 0);
// 6
// Transform an object — multiply all values by 2
reduce({ a: 1, b: 2, c: 3 }, (acc, val, key) => {
acc[key] = val * 2;
return acc;
}, {});
// { a: 2, b: 4, c: 6 }
The third argument is the initial accumulator value — the empty envelope you start with. For sums it’s 0. For object transformations it’s {}. For arrays it’s [].
_.reduceRight does the same thing but right-to-left:
reduceRight([['a', 'b'], ['c', 'd']], (acc, val) => acc.concat(val), []);
// ['c', 'd', 'a', 'b']
Searching
_.find and _.findLast — Find the First (or Last) Match
_.find returns the first element matching your criteria — like scanning a list and stopping as soon as you find what you need.
import find from 'lodash/find';
import findLast from 'lodash/findLast';
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 25 },
];
// Find by matching object properties
find(users, { age: 25 });
// { id: 1, name: 'Alice', age: 25 } — returns FIRST match
// Find with a predicate function
find(users, user => user.name === 'Bob');
// { id: 2, name: 'Bob', age: 30 }
// findLast searches from the END
findLast(users, { age: 25 });
// { id: 3, name: 'Charlie', age: 25 }
Critical distinction: _.find returns a single element (or undefined). _.filter returns an array (possibly empty). Confusing these is one of the most common bugs:
const result = find(users, { age: 25 });
result.name; // Works — 'Alice'
const results = filter(users, { age: 25 });
results.name; // undefined! results is an array, not an object
_.includes — “Is This in There?”
Checks if a value exists in arrays, strings, or objects:
import includes from 'lodash/includes';
includes([1, 2, 3], 2); // true
includes('hello', 'ell'); // true
includes({ a: 1, b: 2 }, 1); // true
includes({ a: 1, b: 2 }, 3); // false
_.some and _.every — “Does Any / Do All Meet the Condition?”
_.some is like asking “is anyone home?” — returns true if at least one passes. _.every is like “did everyone pass the test?” — returns true only if all pass.
import some from 'lodash/some';
import every from 'lodash/every';
some([1, 2, 3], n => n > 2); // true (3 is > 2)
every([1, 2, 3], n => n > 0); // true (all are > 0)
every([1, 2, 3], n => n > 2); // false (1 and 2 are not > 2)
// Works on objects too
every({ a: 'apple', b: 'avocado' }, v => v.startsWith('a')); // true
Grouping & Aggregation
_.groupBy — Sort Items Into Buckets
Think of _.groupBy as sorting laundry. You have a pile of clothes, and you sort them into buckets: whites, darks, delicates. Each bucket gets a label, and all matching items go in.
import groupBy from 'lodash/groupBy';
const words = ['one', 'two', 'three', 'four', 'five'];
// Group by word length
groupBy(words, 'length');
// { '3': ['one', 'two'], '5': ['three'], '4': ['four', 'five'] }
// Group array of objects by a property
const people = [
{ name: 'Alice', role: 'admin' },
{ name: 'Bob', role: 'user' },
{ name: 'Charlie', role: 'admin' },
];
groupBy(people, 'role');
// { admin: [Alice, Charlie], user: [Bob] }
_.keyBy — Create a Lookup Table
Unlike _.groupBy which creates buckets (arrays), _.keyBy creates a dictionary (single object) where each key maps to one item. If two items have the same key, the last one wins.
import keyBy from 'lodash/keyBy';
keyBy(people, 'name');
// {
// Alice: { name: 'Alice', role: 'admin' },
// Bob: { name: 'Bob', role: 'user' },
// Charlie: { name: 'Charlie', role: 'admin' }
// }
// Now you can look up by name instantly:
const lookup = keyBy(people, 'name');
lookup['Alice']; // { name: 'Alice', role: 'admin' }
_.countBy — Tally Occurrences
Like _.groupBy but returns counts instead of arrays:
import countBy from 'lodash/countBy';
countBy(words, 'length');
// { '3': 2, '5': 1, '4': 2 }
countBy([1, 1, 2, 3, 3, 3, 4], n => n);
// { '1': 2, '2': 1, '3': 3, '4': 1 }
Array Operations
_.chunk — Split Into Groups
Splits an array into fixed-size groups — like dividing a deck of cards into piles:
import chunk from 'lodash/chunk';
chunk(['a', 'b', 'c', 'd', 'e'], 2);
// [['a', 'b'], ['c', 'd'], ['e']]
chunk([1, 2, 3, 4], 1);
// [[1], [2], [3], [4]]
_.compact — Remove Falsy Values
Removes all falsy values (false, null, 0, "", undefined, NaN) — like shaking a sieve to let the dust fall through:
import compact from 'lodash/compact';
compact([0, 1, false, 2, '', 3, null, undefined, NaN]);
// [1, 2, 3]
_.uniq — Remove Duplicates
import uniq from 'lodash/uniq';
import sortedUniq from 'lodash/sortedUniq';
uniq([2, 1, 2, 3, 1, 4]);
// [2, 1, 3, 4]
// sortedUniq is faster if your array is already sorted
sortedUniq([1, 1, 2, 3, 3, 4]);
// [1, 2, 3, 4]
// uniqBy for object arrays
uniqBy([{ n: 1 }, { n: 2 }, { n: 1 }], 'n');
// [{ n: 1 }, { n: 2 }]
_.union, _.intersection, _.difference — Set Operations
Like Venn diagram operations for arrays:
import union from 'lodash/union';
import intersection from 'lodash/intersection';
import difference from 'lodash/difference';
const A = [1, 2, 3, 4];
const B = [3, 4, 5, 6];
union(A, B); // [1, 2, 3, 4, 5, 6] — everything from both
intersection(A, B); // [3, 4] — present in both
difference(A, B); // [1, 2] — in A but not B
difference(B, A); // [5, 6] — in B but not A
_.flatten and _.flattenDeep — Un-nest Arrays
import flatten from 'lodash/flatten';
import flattenDeep from 'lodash/flattenDeep';
flatten([1, [2, [3, [4]], 5]]);
// [1, 2, [3, [4]], 5] — one level only
flattenDeep([1, [2, [3, [4]], 5]]);
// [1, 2, 3, 4, 5] — all the way down
_.sortBy and _.orderBy — Sorting
_.sortBy sorts ascending. _.orderBy lets you specify direction per field:
import sortBy from 'lodash/sortBy';
import orderBy from 'lodash/orderBy';
const users = [
{ name: 'Alice', age: 30 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 30 },
];
sortBy(users, 'age');
// [Bob(25), Alice(30), Charlie(30)]
orderBy(users, ['age', 'name'], ['asc', 'desc']);
// [Bob(25), Charlie(30), Alice(30)]
Common Mistakes
1. Mutating Source Data in _.reduce
const items = [{ id: 1 }, { id: 2 }];
// ❌ Mutates the original items
const result = reduce(items, (acc, item) => {
acc[item.id] = item; // Stores reference to original item
return acc;
}, {});
// ✅ Creates copies
const result = reduce(items, (acc, item) => ({
...acc,
[item.id]: { ...item }
}), {});2. Confusing _.find with _.filter
_.find returns one element, _.filter returns an array. Always check which return type your code expects.
3. Relying on _.groupBy Key Order
JavaScript object keys have insertion order for strings, but relying on it is fragile. Use _.orderBy if sort order matters.
4. Using _.chunk with Non-Integer Size
// ❌ chunk('a', 2) would wrap the string
chunk('abc', 2); // ['ab', 'c'] — works on strings too, but may be unexpected
5. Forgetting That _.union Removes Duplicates
_.union returns unique values from all arrays. If you need to preserve duplicates, use _.concat:
// union removes duplicates
union([1, 1, 2], [2, 3]); // [1, 2, 3]
// concat preserves them
[1, 1, 2].concat([2, 3]); // [1, 1, 2, 2, 3]
Practice Questions
1. What does _.compact([0, null, 'hello', undefined, false, 42]) return?
Answer: ['hello', 42]. All falsy values (0, null, undefined, false) are removed.
2. What is the difference between _.find and _.filter?
Answer: _.find returns the first matching element (or undefined). _.filter returns an array of all matching elements (possibly empty).
3. How would you group an array of objects by a property and count occurrences?
Answer: Use _.countBy(collection, 'propertyName'). For example, _.countBy(users, 'role') returns { admin: 2, user: 1 }.
4. Explain _.keyBy vs _.groupBy in one sentence each.
Answer: _.groupBy creates buckets (arrays keyed by category); _.keyBy creates a lookup table (one item per key, last wins).
Challenge
You have an array of file scan results from Durga Antivirus Pro: [{ file: 'a.exe', threat: 'trojan', severity: 8 }, { file: 'b.pdf', threat: null, severity: 0 }, { file: 'c.exe', threat: 'ransomware', severity: 9 }, { file: 'd.doc', threat: null, severity: 0 }]. Use Lodash methods to: filter only files with threats, sort by severity descending, take the top 2 most severe, and extract just their filenames. Expected output: ['c.exe', 'a.exe'].
FAQ
Try It Yourself
Build a transformation pipeline with live preview and performance timing:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lodash Data Transformer</title>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; padding: 2rem; }
.container { max-width: 1200px; margin: 0 auto; }
h1 { font-size: 1.75rem; margin-bottom: 0.25rem; }
.subtitle { color: #94a3b8; margin-bottom: 2rem; }
.layout { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.card { background: #1e293b; border-radius: 0.75rem; padding: 1.5rem; border: 1px solid #334155; }
.card h2 { font-size: 1.05rem; margin-bottom: 0.75rem; color: #38bdf8; }
.card h3 { font-size: 0.9rem; color: #94a3b8; margin-bottom: 0.5rem; text-transform: uppercase; letter-spacing: 0.05em; }
textarea { width: 100%; background: #0f172a; color: #e2e8f0; border: 1px solid #334155; border-radius: 0.375rem; padding: 0.625rem; font-family: 'JetBrains Mono', monospace; font-size: 0.8125rem; min-height: 150px; resize: vertical; }
.step { background: #0f172a; border: 1px solid #334155; border-radius: 0.375rem; padding: 0.75rem; margin-bottom: 0.5rem; }
.step-header { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; flex-wrap: wrap; }
.step-header select { background: #1e293b; color: #e2e8f0; border: 1px solid #475569; border-radius: 0.25rem; padding: 0.25rem 0.5rem; font-size: 0.8rem; }
.step-header input { background: #1e293b; color: #e2e8f0; border: 1px solid #475569; border-radius: 0.25rem; padding: 0.25rem 0.5rem; font-size: 0.8rem; flex: 1; min-width: 100px; font-family: monospace; }
.btn { background: #38bdf8; color: #0f172a; border: none; padding: 0.4rem 1rem; border-radius: 0.375rem; font-weight: 600; cursor: pointer; font-size: 0.85rem; transition: background 0.2s; }
.btn:hover { background: #7dd3fc; }
.btn-sm { padding: 0.25rem 0.5rem; font-size: 0.75rem; }
.btn-outline { background: transparent; color: #38bdf8; border: 1px solid #38bdf8; }
.btn-outline:hover { background: #38bdf8; color: #0f172a; }
.btn-danger { background: #ef4444; color: #fff; border: none; padding: 0.4rem 0.75rem; border-radius: 0.375rem; font-weight: 600; cursor: pointer; font-size: 0.75rem; }
.btn-danger:hover { background: #dc2626; }
.output-box { background: #0f172a; border: 1px solid #334155; border-radius: 0.375rem; padding: 0.75rem; min-height: 100px; max-height: 300px; overflow: auto; font-family: monospace; font-size: 0.8rem; white-space: pre-wrap; word-break: break-all; margin-top: 0.5rem; }
.output-box.success { border-color: #22c55e; }
.output-box.error { border-color: #ef4444; color: #fca5a5; }
.flex { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.stat-row { display: flex; gap: 1.5rem; margin-top: 0.75rem; font-size: 0.8rem; }
.stat-item { color: #94a3b8; }
.stat-item strong { color: #38bdf8; }
.pipeline-preview { font-family: monospace; font-size: 0.75rem; color: #94a3b8; margin-top: 0.5rem; padding: 0.5rem; background: #0f172a; border-radius: 0.25rem; border: 1px dashed #334155; }
.draggable { cursor: grab; }
.draggable:active { cursor: grabbing; }
@media (max-width: 768px) { .layout { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<div class="container">
<h1>📊 Data Transformer</h1>
<p class="subtitle">Build a pipeline of Lodash operations and preview results</p>
<div class="layout">
<!-- Input -->
<div class="card">
<h2>Input Array</h2>
<textarea id="inputData">[
{ "name": "Alice", "age": 25, "score": 88, "active": true },
{ "name": "Bob", "age": 30, "score": 72, "active": false },
{ "name": "Charlie", "age": 22, "score": 95, "active": true },
{ "name": "Diana", "age": 28, "score": 64, "active": true },
{ "name": "Eve", "age": 35, "score": 91, "active": false },
{ "name": "Frank", "age": 19, "score": 45, "active": true }
]</textarea>
<div class="flex" style="margin-top:0.5rem;">
<button class="btn btn-outline btn-sm" onclick="loadSample('users')">Sample: Users</button>
<button class="btn btn-outline btn-sm" onclick="loadSample('numbers')">Sample: Numbers</button>
<button class="btn btn-outline btn-sm" onclick="loadSample('words')">Sample: Words</button>
</div>
</div>
<!-- Pipeline -->
<div class="card">
<h2>Pipeline</h2>
<div id="stepsContainer"></div>
<div class="flex">
<button class="btn btn-sm" onclick="addStep()">+ Add Step</button>
<button class="btn btn-outline btn-sm" onclick="resetPipeline()">Reset</button>
</div>
<div class="pipeline-preview" id="pipelinePreview">Pipeline: input → (none)</div>
</div>
<!-- Output -->
<div class="card" style="grid-column:1/-1;">
<div class="flex" style="justify-content:space-between;">
<h2>Result</h2>
<button class="btn" onclick="runPipeline()">▶ Run</button>
</div>
<div id="outputArea" class="output-box">Click "Run" to execute the pipeline</div>
<div class="stat-row">
<span class="stat-item">Items in: <strong id="inCount">—</strong></span>
<span class="stat-item">Items out: <strong id="outCount">—</strong></span>
<span class="stat-item">Time: <strong id="execTime">—</strong></span>
<span class="stat-item">Status: <strong id="execStatus" style="color:#fbbf24;">Ready</strong></span>
</div>
</div>
</div>
</div>
<script>
const INPUT = document.getElementById('inputData');
const STEPS = document.getElementById('stepsContainer');
const PREVIEW = document.getElementById('pipelinePreview');
const OUTPUT = document.getElementById('outputArea');
const IN_CNT = document.getElementById('inCount');
const OUT_CNT = document.getElementById('outCount');
const EX_TIME = document.getElementById('execTime');
const EX_STAT = document.getElementById('execStatus');
const STEP_TYPES = [
{ value: 'filter', label: '_.filter(predicate)', needsArg: true, argPlaceholder: 'x => x.active' },
{ value: 'map', label: '_.map(transform)', needsArg: true, argPlaceholder: 'x => ({...x, bonus: x.score + 5})' },
{ value: 'reject', label: '_.reject(predicate)', needsArg: true, argPlaceholder: 'x => x.age < 21' },
{ value: 'take', label: '_.take(n)', needsArg: true, argPlaceholder: '3' },
{ value: 'sortBy', label: '_.sortBy(key)', needsArg: true, argPlaceholder: "'age'" },
{ value: 'orderBy', label: '_.orderBy(key, dir)', needsArg: true, argPlaceholder: "['age'], ['asc']" },
{ value: 'groupBy', label: '_.groupBy(key)', needsArg: true, argPlaceholder: "'active'" },
{ value: 'uniq', label: '_.uniq', needsArg: false },
{ value: 'uniqBy', label: '_.uniqBy(iteratee)', needsArg: true, argPlaceholder: "'name'" },
{ value: 'compact', label: '_.compact', needsArg: false },
{ value: 'chunk', label: '_.chunk(size)', needsArg: true, argPlaceholder: '2' },
{ value: 'flatten', label: '_.flatten', needsArg: false },
{ value: 'flattenDeep', label: '_.flattenDeep', needsArg: false },
{ value: 'countBy', label: '_.countBy(iteratee)', needsArg: true, argPlaceholder: "'age'" },
{ value: 'keyBy', label: '_.keyBy(key)', needsArg: true, argPlaceholder: "'name'" },
{ value: 'slice', label: '_.slice(start, end)', needsArg: true, argPlaceholder: '0, 3' },
];
function addStep(type, arg) {
const div = document.createElement('div');
div.className = 'step';
div.innerHTML = `
<div class="step-header">
<select class="step-type" onchange="onStepChange(this)">
${STEP_TYPES.map(t => `<option value="${t.value}" ${t.value === (type || 'filter') ? 'selected' : ''}>${t.label}</option>`).join('')}
</select>
<input class="step-arg" placeholder="${STEP_TYPES.find(t => t.value === (type || 'filter'))?.argPlaceholder || ''}" value="${arg || ''}" />
<button class="btn-danger btn-sm" onclick="this.closest('.step').remove(); updatePreview();">✕</button>
</div>
`;
STEPS.appendChild(div);
updatePreview();
}
function onStepChange(select) {
const step = select.closest('.step');
const input = step.querySelector('.step-arg');
const type = STEP_TYPES.find(t => t.value === select.value);
input.placeholder = type?.argPlaceholder || '';
if (!type?.needsArg) input.style.display = 'none';
else input.style.display = '';
updatePreview();
}
function updatePreview() {
const steps = document.querySelectorAll('.step');
if (steps.length === 0) { PREVIEW.textContent = 'Pipeline: input → (none)'; return; }
const parts = ['input'];
steps.forEach(s => {
const sel = s.querySelector('.step-type');
const arg = s.querySelector('.step-arg');
const label = sel.options[sel.selectedIndex]?.text || sel.value;
if (arg && arg.value && arg.style.display !== 'none') {
parts.push(`${sel.value}(${arg.value})`);
} else {
parts.push(sel.value);
}
});
PREVIEW.textContent = 'Pipeline: ' + parts.join(' → ');
}
function resetPipeline() {
STEPS.innerHTML = '';
addStep('filter', 'x => x.active');
addStep('map', 'x => ({ name: x.name, score: x.score })');
addStep('orderBy', "['score'], ['desc']");
addStep('take', '3');
updatePreview();
}
function loadSample(type) {
if (type === 'numbers') {
INPUT.value = '[' + _.times(20, () => _.random(1, 100)).join(', ') + ']';
} else if (type === 'words') {
INPUT.value = JSON.stringify(['apple', 'banana', 'apple', 'cherry', 'banana', 'date', 'elderberry', 'fig', 'grape', 'apple'], null, 2);
} else {
INPUT.value = `[
{ "name": "Alice", "age": 25, "score": 88, "active": true },
{ "name": "Bob", "age": 30, "score": 72, "active": false },
{ "name": "Charlie", "age": 22, "score": 95, "active": true },
{ "name": "Diana", "age": 28, "score": 64, "active": true },
{ "name": "Eve", "age": 35, "score": 91, "active": false },
{ "name": "Frank", "age": 19, "score": 45, "active": true }
]`;
}
}
function runPipeline() {
let data;
try { data = JSON.parse(INPUT.value); }
catch { OUTPUT.textContent = '❌ Invalid JSON in input'; OUTPUT.className = 'output-box error'; return; }
if (!Array.isArray(data)) { OUTPUT.textContent = '❌ Input must be an array'; OUTPUT.className = 'output-box error'; return; }
const steps = document.querySelectorAll('.step');
if (steps.length === 0) { OUTPUT.textContent = JSON.stringify(data, null, 2); OUTPUT.className = 'output-box success'; return; }
IN_CNT.textContent = data.length;
EX_STAT.textContent = 'Running...';
EX_STAT.style.color = '#fbbf24';
const start = performance.now();
let result;
try {
let chain = _.chain(data);
steps.forEach(s => {
const sel = s.querySelector('.step-type');
const argInput = s.querySelector('.step-arg');
const op = sel.value;
const arg = argInput?.value?.trim() || '';
switch (op) {
case 'filter': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.filter(fn); break; }
case 'map': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.map(fn); break; }
case 'reject': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.reject(fn); break; }
case 'take': { const n = parseInt(arg) || 1; chain = chain.take(n); break; }
case 'sortBy': { chain = arg ? chain.sortBy(eval(`(${arg})`)) : chain.sortBy(); break; }
case 'orderBy': { chain = arg ? chain.orderBy(...eval(`([${arg}])`)) : chain.orderBy(); break; }
case 'groupBy': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.groupBy(fn); break; }
case 'uniq': chain = chain.uniq(); break;
case 'uniqBy': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.uniqBy(fn); break; }
case 'compact': chain = chain.compact(); break;
case 'chunk': { const n = parseInt(arg) || 1; chain = chain.chunk(n); break; }
case 'flatten': chain = chain.flatten(); break;
case 'flattenDeep': chain = chain.flattenDeep(); break;
case 'countBy': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.countBy(fn); break; }
case 'keyBy': { const fn = arg ? eval(`(${arg})`) : _.identity; chain = chain.keyBy(fn); break; }
case 'slice': { const parts = arg.split(',').map(s => parseInt(s.trim())); chain = chain.slice(parts[0] || 0, parts[1]); break; }
}
});
result = chain.value();
} catch (e) { OUTPUT.textContent = '❌ Pipeline error: ' + e.message; OUTPUT.className = 'output-box error'; EX_STAT.textContent = 'Error'; EX_STAT.style.color = '#ef4444'; return; }
const end = performance.now();
const time = (end - start).toFixed(3);
OUTPUT.textContent = JSON.stringify(result, null, 2);
OUTPUT.className = 'output-box success';
OUT_CNT.textContent = Array.isArray(result) ? result.length : Object.keys(result).length;
EX_TIME.textContent = time + ' ms';
EX_STAT.textContent = '✅ Success';
EX_STAT.style.color = '#22c55e';
}
resetPipeline();
</script>
</body>
</html>What’s Next
| Step | Topic | Why |
|---|---|---|
| https://tutorials.dodatech.com/frontend/libraries/lodash/lodash-objects-functions/ | Deep cloning, merging, _.get, _.debounce, _.throttle | Handle complex objects and optimize event handling |
| https://tutorials.dodatech.com/frontend/libraries/lodash/lodash-utilities/ | String utilities, math, type checking, lazy evaluation | Complete your Lodash skillset |
| https://tutorials.dodatech.com/frontend/libraries/lodash/lodash-getting-started/ | Installation, imports, chaining fundamentals | Review basics if needed |
| Node.js Data Processing | Apply Lodash in server-side data pipelines | Real-world backend applications |
| JSON Data Handling | Working with JSON data in JavaScript | Essential for API data transformations |
What’s Next
Congratulations on completing this Lodash Collections Arrays tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro