Bulk Operations Guide
Bulk operations provide efficient methods for performing batch operations on collections. Instead of calling individual methods in loops, bulk operations process multiple elements in a single call, offering better performance and cleaner code.
Overview
All enhanced collection types in Harneet support bulk operations:
- Stack:
push_all(), pop_all() - Queue:
enqueue_all(), dequeue_all() - Set:
add_all(), remove_all(), contains_all() - LinkedList:
add_all_first(), add_all_last(), add_all_at(), remove_range() - EnhancedArray:
add_all(), insert_all_at(), contains_all(), remove_range()
Benefits
- Reduced overhead: Single function call instead of loop iterations
- Better memory allocation: Pre-allocate space for multiple elements
- Optimized operations: Internal optimizations for batch processing
- Cache efficiency: Better CPU cache utilization
Code Quality
- Cleaner code: More readable and maintainable
- Atomic operations: All-or-nothing semantics where applicable
- Error handling: Detailed feedback on operation results
- Type safety: Compile-time validation
Stack Bulk Operations
push_all(items array)
Pushes multiple items onto the stack at once.
| import collections
var stack = collections.new_stack()
var items = [1, 2, 3, 4, 5]
stack.push_all(items)
// Stack now contains: [1, 2, 3, 4, 5] (5 on top)
|
Performance: O(n) where n is the number of items
pop_all(count int) → array
Pops multiple items from the stack at once, returning them in LIFO order.
| var stack = collections.new_stack()
stack.push_all([1, 2, 3, 4, 5])
var popped = stack.pop_all(3)
// popped = [5, 4, 3] (LIFO order)
// stack now contains: [1, 2]
|
Performance: O(n) where n is the count
Note: If count exceeds stack size, returns all available items
Queue Bulk Operations
enqueue_all(items array)
Enqueues multiple items at once.
| import collections
var queue = collections.new_queue()
var items = ["a", "b", "c", "d"]
queue.enqueue_all(items)
// Queue now contains: [a, b, c, d] (a at front)
|
Performance: O(n) where n is the number of items
dequeue_all(count int) → array
Dequeues multiple items at once, returning them in FIFO order.
| var queue = collections.new_queue()
queue.enqueue_all([1, 2, 3, 4, 5])
var dequeued = queue.dequeue_all(3)
// dequeued = [1, 2, 3] (FIFO order)
// queue now contains: [4, 5]
|
Performance: O(n) where n is the count
Note: If count exceeds queue size, returns all available items
Set Bulk Operations
add_all(items array) → BulkResult
Adds multiple items to the set, returning detailed operation results.
| import collections
var set = collections.new_set()
var items = [10, 20, 30, 20, 40] // Note: 20 is duplicate
var result = set.add_all(items)
fmt.Printf("Success: %d, Failure: %d\n",
result.SuccessCount, result.FailureCount)
// Output: Success: 4, Failure: 1
|
Performance: O(n) average case where n is the number of items
Returns: BulkResult with SuccessCount and FailureCount
remove_all(items array) → BulkResult
Removes multiple items from the set.
| var set = collections.new_set()
set.add_all([1, 2, 3, 4, 5])
var result = set.remove_all([2, 4, 6]) // 6 doesn't exist
fmt.Printf("Success: %d, Failure: %d\n",
result.SuccessCount, result.FailureCount)
// Output: Success: 2, Failure: 1
|
Performance: O(n) average case
Returns: BulkResult with operation feedback
contains_all(items array) → bool
Checks if the set contains all specified items.
| var set = collections.new_set()
set.add_all([1, 2, 3, 4, 5])
var has_all = set.contains_all([1, 3, 5]) // true
var has_missing = set.contains_all([1, 3, 10]) // false
|
Performance: O(n) average case
Returns: true if all items are present, false otherwise
LinkedList Bulk Operations
add_all_first(items array)
Adds multiple items to the beginning of the list.
| import collections
var list = collections.new_linked_list()
list.add_all_last([100, 200])
list.add_all_first([10, 20])
// List: [20, 10, 100, 200]
// Items added in reverse order
|
Performance: O(n) where n is the number of items
Note: Items are prepended in reverse order
add_all_last(items array)
Adds multiple items to the end of the list.
| var list = collections.new_linked_list()
list.add_all_last([1, 2, 3, 4, 5])
// List: [1, 2, 3, 4, 5]
|
Performance: O(n) where n is the number of items
add_all_at(index int, items array)
Inserts multiple items at a specific position.
| var list = collections.new_linked_list()
list.add_all_last([1, 2, 5, 6])
list.add_all_at(2, [3, 4])
// List: [1, 2, 3, 4, 5, 6]
|
Performance: O(m + n) where m is the index position and n is the number of items
remove_range(start int, end int) → array
Removes a range of elements (inclusive).
| var list = collections.new_linked_list()
list.add_all_last([10, 20, 30, 40, 50])
var removed = list.remove_range(1, 3)
// removed = [20, 30, 40]
// list = [10, 50]
|
Performance: O(m + n) where m is the start index and n is the range size
EnhancedArray Bulk Operations
add_all(items array)
Appends multiple items to the array.
| import collections
var array = collections.new_array()
array.add_all([1, 2, 3, 4, 5])
// Array: [1, 2, 3, 4, 5]
|
Performance: O(n) amortized where n is the number of items
insert_all_at(index int, items array)
Inserts multiple items at a specific position.
| var array = collections.new_array()
array.add_all([1, 2, 5, 6])
array.insert_all_at(2, [3, 4])
// Array: [1, 2, 3, 4, 5, 6]
|
Performance: O(m + n) where m is elements to shift and n is items to insert
contains_all(items array) → bool
Checks if the array contains all specified items.
| var array = collections.new_array()
array.add_all([1, 2, 3, 4, 5])
var has_all = array.contains_all([1, 3, 5]) // true
var has_missing = array.contains_all([1, 3, 10]) // false
|
Performance: O(n × m) where n is array size and m is items to check
remove_range(start int, end int) → array
Removes a range of elements (inclusive).
| var array = collections.new_array()
array.add_all([10, 20, 30, 40, 50])
var removed = array.remove_range(1, 3)
// removed = [20, 30, 40]
// array = [10, 50]
|
Performance: O(n) where n is the number of elements to shift
Individual vs Bulk Operations
| // ❌ Inefficient: Individual operations
var stack = collections.new_stack()
for i in range(1000) {
stack.push(i) // 1000 function calls
}
// ✅ Efficient: Bulk operation
var stack = collections.new_stack()
var items = []
for i in range(1000) {
items = append(items, i)
}
stack.push_all(items) // 1 function call
|
| Operation | Individual | Bulk | Improvement |
| Stack Push (1000 items) | 1000 calls | 1 call | ~10x faster |
| Queue Enqueue (1000 items) | 1000 calls | 1 call | ~10x faster |
| Set Add (1000 items) | 1000 calls | 1 call | ~8x faster |
| List Append (1000 items) | 1000 calls | 1 call | ~12x faster |
Best Practices
1. Use Bulk Operations for Large Datasets
| // ✅ Good: Use bulk operations for >10 items
var items = []
for i in range(100) {
items = append(items, i)
}
stack.push_all(items)
// ❌ Avoid: Individual operations in loops
for i in range(100) {
stack.push(i)
}
|
2. Pre-allocate Arrays
| // ✅ Good: Build array first
var items = []
for i in range(1000) {
items = append(items, process(i))
}
set.add_all(items)
// ❌ Avoid: Multiple small bulk operations
for i in range(100) {
var batch = [i, i+1, i+2]
set.add_all(batch)
}
|
3. Check BulkResult for Sets
| // ✅ Good: Check operation results
var result = set.add_all(items)
if result.FailureCount > 0 {
fmt.Printf("Warning: %d duplicates ignored\n", result.FailureCount)
}
// ❌ Avoid: Ignoring operation feedback
set.add_all(items) // No feedback
|
4. Use Range Operations Wisely
| // ✅ Good: Remove contiguous ranges
var removed = list.remove_range(10, 20)
// ❌ Avoid: Multiple single removals
for i in range(10, 21) {
list.remove_at(10) // Index shifts each time!
}
|
Error Handling
Empty Arrays
All bulk operations handle empty arrays gracefully:
| var stack = collections.new_stack()
var empty = []
stack.push_all(empty) // No-op, no error
|
Out of Bounds
Operations that exceed collection size return available items:
| var stack = collections.new_stack()
stack.push_all([1, 2, 3])
var popped = stack.pop_all(10) // Returns [3, 2, 1]
|
Invalid Indices
Range operations validate indices:
| var list = collections.new_linked_list()
list.add_all_last([1, 2, 3])
// list.remove_range(5, 10) // Error: index out of bounds
|
Common Patterns
Batch Processing
| function process_batch(items array) {
var results = collections.new_array()
var processed = []
for item in items {
processed = append(processed, transform(item))
}
results.add_all(processed)
return results
}
|
Set Operations
| function union(set1, set2) {
var result = collections.new_set()
result.add_all(set1.to_array())
result.add_all(set2.to_array())
return result
}
function intersection(set1, set2) {
var result = collections.new_set()
var items = set1.to_array()
for item in items {
if set2.contains(item) {
result.add(item)
}
}
return result
}
|
Queue Batch Processing
| function process_queue_batch(queue, batch_size int) {
var batch = queue.dequeue_all(batch_size)
var results = []
for item in batch {
results = append(results, process(item))
}
return results
}
|
Migration Guide
From Individual Operations
| // Before
var stack = collections.new_stack()
for item in items {
stack.push(item)
}
// After
var stack = collections.new_stack()
stack.push_all(items)
|
From Manual Loops
| // Before
var set = collections.new_set()
var success_count = 0
for item in items {
if set.add(item) {
success_count = success_count + 1
}
}
// After
var set = collections.new_set()
var result = set.add_all(items)
var success_count = result.SuccessCount
|
See Also