or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-collections.mdbags.mdbidimaps.mdcollection-utilities.mdfunctional-programming.mdindex.mdmultimaps.md

advanced-collections.mddocs/

0

# Advanced Collections

1

2

Apache Commons Collections provides several specialized collection types for specific use cases including tries (prefix trees), bloom filters, advanced queues, and sophisticated iterators.

3

4

## Trie Collections (Prefix Trees)

5

6

Tries are tree-based data structures optimized for prefix-based operations on strings or sequences.

7

8

### Trie<K, V> Interface

9

10

```java { .api }

11

import org.apache.commons.collections4.Trie;

12

import org.apache.commons.collections4.trie.PatriciaTrie;

13

import java.util.SortedMap;

14

15

Trie<String, Integer> trie = new PatriciaTrie<>();

16

17

// Add key-value pairs

18

trie.put("cat", 1);

19

trie.put("car", 2);

20

trie.put("card", 3);

21

trie.put("care", 4);

22

trie.put("careful", 5);

23

trie.put("dog", 6);

24

25

// Standard map operations

26

Integer value = trie.get("car"); // Returns 2

27

boolean hasKey = trie.containsKey("card"); // true

28

int size = trie.size(); // 6

29

30

// Prefix-based operations

31

SortedMap<String, Integer> carPrefixed = trie.prefixMap("car");

32

// Returns: {car=2, card=3, care=4, careful=5}

33

34

SortedMap<String, Integer> cPrefixed = trie.prefixMap("c");

35

// Returns: {car=2, card=3, care=4, careful=5, cat=1}

36

37

// Empty prefix returns all entries

38

SortedMap<String, Integer> all = trie.prefixMap("");

39

```

40

41

### PatriciaTrie<V> Implementation

42

43

PATRICIA (Practical Algorithm to Retrieve Information Coded in Alphanumeric) trie implementation.

44

45

```java { .api }

46

import org.apache.commons.collections4.trie.PatriciaTrie;

47

import java.util.Map;

48

49

// Create for String keys

50

PatriciaTrie<String> dictionary = new PatriciaTrie<>();

51

52

// Add dictionary entries

53

dictionary.put("apple", "A red or green fruit");

54

dictionary.put("application", "A software program");

55

dictionary.put("apply", "To put to use");

56

dictionary.put("appreciate", "To value or understand");

57

58

// Autocomplete functionality

59

SortedMap<String, String> suggestions = dictionary.prefixMap("app");

60

System.out.println("Words starting with 'app':");

61

suggestions.forEach((word, definition) ->

62

System.out.println(word + ": " + definition));

63

64

// Create from existing map

65

Map<String, Integer> wordCounts = Map.of(

66

"hello", 5,

67

"world", 3,

68

"help", 2,

69

"helper", 1

70

);

71

PatriciaTrie<Integer> countTrie = new PatriciaTrie<>(wordCounts);

72

73

// Find all words with "hel" prefix

74

SortedMap<String, Integer> helWords = countTrie.prefixMap("hel");

75

// Returns: {hello=5, help=2, helper=1}

76

```

77

78

### Trie Use Cases

79

80

#### Autocomplete System

81

82

```java { .api }

83

public class AutocompleteSystem {

84

private final Trie<String, Integer> trie = new PatriciaTrie<>();

85

86

public void addWord(String word, int frequency) {

87

trie.put(word.toLowerCase(), frequency);

88

}

89

90

public List<String> getSuggestions(String prefix, int maxResults) {

91

SortedMap<String, Integer> matches = trie.prefixMap(prefix.toLowerCase());

92

93

return matches.entrySet().stream()

94

.sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) // Sort by frequency

95

.limit(maxResults)

96

.map(Map.Entry::getKey)

97

.collect(Collectors.toList());

98

}

99

100

public boolean hasWord(String word) {

101

return trie.containsKey(word.toLowerCase());

102

}

103

104

public void incrementFrequency(String word) {

105

String key = word.toLowerCase();

106

int currentFreq = trie.getOrDefault(key, 0);

107

trie.put(key, currentFreq + 1);

108

}

109

}

110

```

111

112

#### Phone Directory

113

114

```java { .api }

115

public class PhoneDirectory {

116

private final Trie<String, Contact> byName = new PatriciaTrie<>();

117

private final Trie<String, Contact> byPhone = new PatriciaTrie<>();

118

119

public void addContact(Contact contact) {

120

byName.put(contact.getName().toLowerCase(), contact);

121

byPhone.put(contact.getPhone(), contact);

122

}

123

124

public List<Contact> searchByName(String namePrefix) {

125

return new ArrayList<>(byName.prefixMap(namePrefix.toLowerCase()).values());

126

}

127

128

public List<Contact> searchByPhone(String phonePrefix) {

129

return new ArrayList<>(byPhone.prefixMap(phonePrefix).values());

130

}

131

132

public Contact getExactMatch(String name) {

133

return byName.get(name.toLowerCase());

134

}

135

}

136

```

137

138

## Bloom Filters

139

140

Probabilistic data structures for membership testing with no false negatives but possible false positives.

141

142

### BloomFilter Interface

143

144

```java { .api }

145

import org.apache.commons.collections4.bloomfilter.BloomFilter;

146

import org.apache.commons.collections4.bloomfilter.SimpleBloomFilter;

147

import org.apache.commons.collections4.bloomfilter.Shape;

148

import org.apache.commons.collections4.bloomfilter.Hasher;

149

import org.apache.commons.collections4.bloomfilter.EnhancedDoubleHasher;

150

151

// Create bloom filter shape (size and hash functions)

152

Shape shape = Shape.fromEstimates(1000, 0.01); // Expected elements: 1000, false positive rate: 1%

153

154

BloomFilter filter = new SimpleBloomFilter(shape);

155

156

// Add elements (using hashers)

157

Hasher hasher1 = new EnhancedDoubleHasher("element1".hashCode(), "element1".hashCode());

158

Hasher hasher2 = new EnhancedDoubleHasher("element2".hashCode(), "element2".hashCode());

159

160

filter.merge(hasher1);

161

filter.merge(hasher2);

162

163

// Test membership

164

boolean mayContain1 = filter.contains(hasher1); // true (definitely in set)

165

Hasher hasher3 = new EnhancedDoubleHasher("element3".hashCode(), "element3".hashCode());

166

boolean mayContain3 = filter.contains(hasher3); // false or true (maybe in set)

167

168

// Get filter statistics

169

int cardinality = filter.cardinality(); // Number of set bits

170

Shape filterShape = filter.getShape(); // Configuration details

171

```

172

173

### CountingBloomFilter Interface

174

175

Allows removal of elements by maintaining counts.

176

177

```java { .api }

178

import org.apache.commons.collections4.bloomfilter.CountingBloomFilter;

179

180

CountingBloomFilter countingFilter = new ArrayCountingBloomFilter(shape);

181

182

// Add elements

183

countingFilter.merge(hasher1);

184

countingFilter.merge(hasher1); // Add same element twice

185

186

// Remove elements

187

boolean removed = countingFilter.remove(hasher1); // Decrements count

188

boolean removedAgain = countingFilter.remove(hasher1); // Decrements to zero

189

190

// Element no longer in filter

191

boolean stillThere = countingFilter.contains(hasher1); // false

192

```

193

194

### Bloom Filter Use Cases

195

196

#### Caching Layer

197

198

```java { .api }

199

public class CacheWithBloomFilter<K, V> {

200

private final Map<K, V> cache = new HashMap<>();

201

private final BloomFilter filter;

202

private final Function<K, Hasher> hasherFunction;

203

204

public CacheWithBloomFilter(Shape shape, Function<K, Hasher> hasherFunction) {

205

this.filter = new SimpleBloomFilter(shape);

206

this.hasherFunction = hasherFunction;

207

}

208

209

public void put(K key, V value) {

210

cache.put(key, value);

211

filter.merge(hasherFunction.apply(key));

212

}

213

214

public V get(K key) {

215

// Fast negative check - if not in bloom filter, definitely not in cache

216

if (!filter.contains(hasherFunction.apply(key))) {

217

return null; // Definitely not in cache

218

}

219

220

// May or may not be in cache - check actual cache

221

return cache.get(key);

222

}

223

224

public boolean mightContain(K key) {

225

return filter.contains(hasherFunction.apply(key));

226

}

227

}

228

```

229

230

### Additional Bloom Filter Implementations

231

232

Apache Commons Collections provides several specialized bloom filter implementations for different use cases.

233

234

```java { .api }

235

import org.apache.commons.collections4.bloomfilter.ArrayCountingBloomFilter;

236

import org.apache.commons.collections4.bloomfilter.BitMapBloomFilter;

237

import org.apache.commons.collections4.bloomfilter.LayeredBloomFilter;

238

239

// Array-based counting bloom filter (supports removal)

240

ArrayCountingBloomFilter countingFilter = new ArrayCountingBloomFilter(shape);

241

countingFilter.merge(hasher1);

242

countingFilter.merge(hasher1); // Add twice

243

boolean removed = countingFilter.remove(hasher1); // Remove once

244

245

// Bitmap-based bloom filter for memory efficiency

246

BitMapBloomFilter bitMapFilter = new BitMapBloomFilter(shape);

247

bitMapFilter.merge(hasher1);

248

boolean contains = bitMapFilter.contains(hasher1); // Fast membership test

249

250

// Layered bloom filter for time-based data

251

LayeredBloomFilter layeredFilter = new LayeredBloomFilter(shape, 3); // 3 layers

252

layeredFilter.merge(hasher1);

253

layeredFilter.next(); // Advance to next layer

254

layeredFilter.merge(hasher2);

255

```

256

257

### Bloom Filter Shape Configuration

258

259

The Shape class configures bloom filter parameters for optimal performance.

260

261

```java { .api }

262

import org.apache.commons.collections4.bloomfilter.Shape;

263

264

// Create shape from estimates

265

Shape fromEstimates = Shape.fromEstimates(1000, 0.01); // 1000 items, 1% false positive rate

266

267

// Create shape from parameters

268

Shape fromParams = Shape.fromNP(1000, 10); // 1000 items, 10 hash functions

269

270

// Get shape properties

271

int numberOfBits = fromEstimates.getNumberOfBits(); // Total bits in filter

272

int numberOfHashFunctions = fromEstimates.getNumberOfHashFunctions(); // Hash functions used

273

double probability = fromEstimates.getProbability(500); // False positive rate at 500 items

274

275

// Calculate optimal parameters for different scenarios

276

int optimalBits = Shape.calculateNumberOfBits(1000, 0.01); // Bits needed

277

int optimalHashes = Shape.calculateNumberOfHashFunctions(1000, 9600); // Hash functions needed

278

```

279

280

## Advanced Queue Implementations

281

282

### CircularFifoQueue<E>

283

284

A fixed-size queue that overwrites the oldest element when full.

285

286

```java { .api }

287

import org.apache.commons.collections4.queue.CircularFifoQueue;

288

289

// Create with default size (32)

290

CircularFifoQueue<String> defaultQueue = new CircularFifoQueue<>();

291

292

// Create with specific size

293

CircularFifoQueue<Integer> numbers = new CircularFifoQueue<>(5);

294

295

// Add elements

296

numbers.offer(1);

297

numbers.offer(2);

298

numbers.offer(3);

299

numbers.offer(4);

300

numbers.offer(5);

301

302

System.out.println(numbers); // [1, 2, 3, 4, 5]

303

304

// Adding when full overwrites oldest

305

numbers.offer(6); // Overwrites 1

306

numbers.offer(7); // Overwrites 2

307

308

System.out.println(numbers); // [3, 4, 5, 6, 7]

309

310

// Queue properties

311

boolean isFull = numbers.isFull(); // true

312

int maxSize = numbers.maxSize(); // 5

313

int currentSize = numbers.size(); // 5

314

315

// Create from existing collection (takes only last N elements if oversized)

316

List<String> manyItems = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h");

317

CircularFifoQueue<String> fromList = new CircularFifoQueue<>(manyItems); // Takes last 32

318

CircularFifoQueue<String> fromListSized = new CircularFifoQueue<>(3, manyItems); // Takes "f", "g", "h"

319

```

320

321

### Queue Decorators

322

323

```java { .api }

324

import org.apache.commons.collections4.QueueUtils;

325

import org.apache.commons.collections4.Predicate;

326

import org.apache.commons.collections4.Transformer;

327

import java.util.LinkedList;

328

import java.util.Queue;

329

330

Queue<String> baseQueue = new LinkedList<>();

331

332

// Synchronized queue

333

Queue<String> syncQueue = QueueUtils.synchronizedQueue(baseQueue);

334

335

// Unmodifiable queue

336

baseQueue.offer("item1");

337

baseQueue.offer("item2");

338

Queue<String> readOnlyQueue = QueueUtils.unmodifiableQueue(baseQueue);

339

340

// Predicated queue (validates additions)

341

Predicate<String> nonEmpty = s -> s != null && !s.trim().isEmpty();

342

Queue<String> validatedQueue = QueueUtils.predicatedQueue(new LinkedList<>(), nonEmpty);

343

344

validatedQueue.offer("valid"); // Success

345

try {

346

validatedQueue.offer(""); // Throws IllegalArgumentException

347

} catch (IllegalArgumentException e) {

348

System.out.println("Empty string rejected");

349

}

350

351

// Transforming queue

352

Transformer<String, String> upperCase = String::toUpperCase;

353

Queue<String> transformingQueue = QueueUtils.transformingQueue(new LinkedList<>(), upperCase);

354

transformingQueue.offer("hello"); // Stored as "HELLO"

355

```

356

357

### Specialized Queue Use Cases

358

359

#### Recent Items Cache

360

361

```java { .api }

362

public class RecentItemsCache<T> {

363

private final CircularFifoQueue<T> recentItems;

364

private final Set<T> itemSet = new LinkedHashSet<>();

365

366

public RecentItemsCache(int maxSize) {

367

this.recentItems = new CircularFifoQueue<>(maxSize);

368

}

369

370

public void addItem(T item) {

371

// Remove if already exists to avoid duplicates

372

if (itemSet.contains(item)) {

373

recentItems.remove(item);

374

itemSet.remove(item);

375

}

376

377

// Add new item

378

if (recentItems.isFull()) {

379

T removed = recentItems.poll();

380

itemSet.remove(removed);

381

}

382

383

recentItems.offer(item);

384

itemSet.add(item);

385

}

386

387

public List<T> getRecentItems() {

388

return new ArrayList<>(recentItems);

389

}

390

391

public boolean isRecent(T item) {

392

return itemSet.contains(item);

393

}

394

}

395

```

396

397

## Advanced Iterators

398

399

### Specialized Iterator Types

400

401

#### OrderedIterator<E>

402

403

Iterator that supports bidirectional navigation.

404

405

```java { .api }

406

import org.apache.commons.collections4.OrderedIterator;

407

import org.apache.commons.collections4.iterators.ListIteratorWrapper;

408

import java.util.List;

409

import java.util.Arrays;

410

411

List<String> list = Arrays.asList("first", "second", "third", "fourth");

412

OrderedIterator<String> iterator = new ListIteratorWrapper<>(list.listIterator());

413

414

// Forward iteration

415

while (iterator.hasNext()) {

416

String item = iterator.next();

417

System.out.println("Forward: " + item);

418

}

419

420

// Backward iteration

421

while (iterator.hasPrevious()) {

422

String item = iterator.previous();

423

System.out.println("Backward: " + item);

424

}

425

```

426

427

#### ResettableIterator<E>

428

429

Iterator that can be reset to its initial position.

430

431

```java { .api }

432

import org.apache.commons.collections4.ResettableIterator;

433

import org.apache.commons.collections4.iterators.ArrayIterator;

434

435

String[] array = {"a", "b", "c", "d"};

436

ResettableIterator<String> resetIterator = new ArrayIterator<>(array);

437

438

// First iteration

439

while (resetIterator.hasNext()) {

440

System.out.println("First pass: " + resetIterator.next());

441

}

442

443

// Reset and iterate again

444

resetIterator.reset();

445

while (resetIterator.hasNext()) {

446

System.out.println("Second pass: " + resetIterator.next());

447

}

448

```

449

450

#### MapIterator<K, V>

451

452

Iterator optimized for map traversal.

453

454

```java { .api }

455

import org.apache.commons.collections4.MapIterator;

456

import org.apache.commons.collections4.map.LinkedMap;

457

458

LinkedMap<String, Integer> map = new LinkedMap<>();

459

map.put("apple", 5);

460

map.put("banana", 3);

461

map.put("cherry", 8);

462

463

MapIterator<String, Integer> mapIterator = map.mapIterator();

464

while (mapIterator.hasNext()) {

465

String key = mapIterator.next();

466

Integer value = mapIterator.getValue();

467

468

// Modify value in-place

469

mapIterator.setValue(value * 2);

470

471

System.out.println(key + " -> " + mapIterator.getValue());

472

}

473

```

474

475

### Iterator Utilities

476

477

#### Chaining Iterators

478

479

```java { .api }

480

import org.apache.commons.collections4.IteratorUtils;

481

import java.util.Iterator;

482

import java.util.Arrays;

483

484

List<String> list1 = Arrays.asList("a", "b", "c");

485

List<String> list2 = Arrays.asList("d", "e", "f");

486

List<String> list3 = Arrays.asList("g", "h", "i");

487

488

// Chain multiple iterators

489

Iterator<String> chained = IteratorUtils.chainedIterator(

490

list1.iterator(),

491

list2.iterator(),

492

list3.iterator()

493

);

494

495

// Iterate through all elements in sequence

496

while (chained.hasNext()) {

497

System.out.println(chained.next()); // a, b, c, d, e, f, g, h, i

498

}

499

```

500

501

#### Filtering Iterators

502

503

```java { .api }

504

import org.apache.commons.collections4.Predicate;

505

506

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

507

508

// Filter even numbers

509

Predicate<Integer> evenPredicate = n -> n % 2 == 0;

510

Iterator<Integer> evenNumbers = IteratorUtils.filteredIterator(numbers.iterator(), evenPredicate);

511

512

System.out.println("Even numbers:");

513

while (evenNumbers.hasNext()) {

514

System.out.println(evenNumbers.next()); // 2, 4, 6, 8, 10

515

}

516

```

517

518

#### Transforming Iterators

519

520

```java { .api }

521

import org.apache.commons.collections4.Transformer;

522

523

List<String> words = Arrays.asList("hello", "world", "java", "collections");

524

525

// Transform to uppercase

526

Transformer<String, String> upperCase = String::toUpperCase;

527

Iterator<String> upperCaseIterator = IteratorUtils.transformedIterator(words.iterator(), upperCase);

528

529

System.out.println("Uppercase words:");

530

while (upperCaseIterator.hasNext()) {

531

System.out.println(upperCaseIterator.next()); // HELLO, WORLD, JAVA, COLLECTIONS

532

}

533

534

// Transform to word lengths

535

Transformer<String, Integer> lengthTransformer = String::length;

536

Iterator<Integer> lengthIterator = IteratorUtils.transformedIterator(words.iterator(), lengthTransformer);

537

```

538

539

#### Collating Iterator

540

541

Merges multiple sorted iterators into a single sorted iterator.

542

543

```java { .api }

544

import java.util.Comparator;

545

546

List<Integer> list1 = Arrays.asList(1, 4, 7, 10); // Sorted

547

List<Integer> list2 = Arrays.asList(2, 5, 8, 11); // Sorted

548

List<Integer> list3 = Arrays.asList(3, 6, 9, 12); // Sorted

549

550

// Merge into single sorted sequence

551

Iterator<Integer> collated = IteratorUtils.collatingIterator(

552

Comparator.naturalOrder(),

553

list1.iterator(),

554

list2.iterator(),

555

list3.iterator()

556

);

557

558

System.out.println("Merged sorted sequence:");

559

while (collated.hasNext()) {

560

System.out.println(collated.next()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

561

}

562

```

563

564

## Performance Considerations

565

566

### Trie Performance

567

568

```java { .api }

569

// Trie operations are O(k) where k is key length, not collection size

570

Trie<String, Object> largeTrie = new PatriciaTrie<>();

571

572

// Adding 1M entries - each operation is O(key_length)

573

for (int i = 0; i < 1_000_000; i++) {

574

largeTrie.put("key" + i, i);

575

}

576

577

// Prefix search is still O(prefix_length + result_size)

578

SortedMap<String, Object> results = largeTrie.prefixMap("key123"); // Fast even with 1M entries

579

```

580

581

### Circular Queue Performance

582

583

```java { .api }

584

// CircularFifoQueue offers O(1) operations

585

CircularFifoQueue<String> efficient = new CircularFifoQueue<>(1000);

586

587

// All operations are constant time

588

efficient.offer("item"); // O(1)

589

String item = efficient.poll(); // O(1)

590

boolean full = efficient.isFull(); // O(1)

591

592

// Much more efficient than removing from front of ArrayList

593

List<String> inefficient = new ArrayList<>();

594

// Adding to end: O(1), removing from front: O(n)

595

```

596

597

### Iterator Memory Usage

598

599

```java { .api }

600

// Memory-efficient iteration over large collections

601

List<String> hugeList = generateHugeList(); // Millions of items

602

603

// Memory efficient - only holds current position

604

Iterator<String> memoryEfficient = hugeList.iterator();

605

606

// Less memory efficient - may hold references to filtered items

607

List<String> filtered = hugeList.stream()

608

.filter(s -> s.startsWith("prefix"))

609

.collect(Collectors.toList());

610

611

// Use iterator utilities for memory-efficient processing

612

Iterator<String> filteredIterator = IteratorUtils.filteredIterator(

613

hugeList.iterator(),

614

s -> s.startsWith("prefix")

615

);

616

```

617

618

## Best Practices

619

620

### Choosing Collection Types

621

622

```java { .api }

623

// Use Trie for prefix-based operations

624

Trie<String, Object> autocomplete = new PatriciaTrie<>(); // Autocomplete, dictionaries

625

626

// Use Bloom Filter for membership pre-filtering

627

BloomFilter membershipFilter = new SimpleBloomFilter(shape); // Cache layers, deduplication

628

629

// Use CircularFifoQueue for fixed-size buffers

630

CircularFifoQueue<LogEntry> logBuffer = new CircularFifoQueue<>(1000); // Recent items, logs

631

632

// Use specialized iterators for complex traversal

633

Iterator<String> complexTraversal = IteratorUtils.chainedIterator(

634

IteratorUtils.filteredIterator(source1.iterator(), predicate1),

635

IteratorUtils.transformedIterator(source2.iterator(), transformer)

636

);

637

```

638

639

### Error Handling

640

641

```java { .api }

642

// Safe trie operations

643

public List<String> safeGetSuggestions(Trie<String, Integer> trie, String prefix) {

644

if (prefix == null || trie == null) {

645

return Collections.emptyList();

646

}

647

648

try {

649

SortedMap<String, Integer> matches = trie.prefixMap(prefix);

650

return new ArrayList<>(matches.keySet());

651

} catch (Exception e) {

652

// Log error and return empty results

653

return Collections.emptyList();

654

}

655

}

656

657

// Safe queue operations

658

public boolean safeOffer(CircularFifoQueue<String> queue, String item) {

659

if (queue == null || item == null) {

660

return false;

661

}

662

663

return queue.offer(item); // Always succeeds for CircularFifoQueue

664

}

665

```

666

667

Advanced collections in Apache Commons Collections provide specialized data structures for specific performance and functionality requirements. Choose the appropriate type based on your access patterns, memory constraints, and performance needs.