iteratez
A powerful functional iterator, transformer, and mutator.
Out of the box you can iterate over arrays, objects, trees, sets, maps, linked-lists, iterables - and you can provide iteration capabilites to your own code no matter how complex the type (dynamically calculated, etc).
The iterator is lazy, so you can chain "views" and iteration is not done until you perform "operations" or "mutations" to the underlying source.
Features
- Array, object, tree, set, map, linked-list, and iterables out of the box.
- Iteration is lazy, so iteration is only done when it absolutely needs to be.
- Some operations can exit early and cease iteration saving time and resources.
- When iterating, you can stop at any time.
- If the underlying source supports it, remove a value.
- If the underlying source supports it, replace a value.
- You can chain views which don't cause iteration until an operation or mutation are called.
- You can call mutations to affect the underlying source.
- You can call operations to iterate and produce a result.
- You can create a reusable function to perform operations repeatedly.
- Create your own iterator.
You can see all of these features in the examples below.
Views
Returns an iterator...
where
: for a subset of the values.not
: for a subset of the values that don't pass test (opposite of where).transform
: that transforms the values to another type.reverse
: that iterates over the values in reverse order.exclude
: that excludes values found in another iterator.intersect
: that has common values in another iterator.sorted
: that is sorted based on some comparison.shuffle
: that is randomly ordered.unique
: that has only unique values.duplicates
: that has all the duplicate values.readonly
: that ignores mutations.keys
: only for the keys of the values (replace not supported).values
: only for the values (new key is index based).take
: that only iterates over the first X values.skip
: that skips the first X values.drop
: that drops off the last X values.append
: that is the original iterator + one or more iterators specified.prepend
: that is one or more iterators specified + the original iterator.gt
: that only has values greater than a value.gte
: that only has values greater than or equal to a value.lt
: that only has values less than a value.lte
: that only has values less than or equal to a value.fork
: that is this, but allows a function to perform fork operationssplit
: Splits the values into two iterators (pass/fail) based on a condition.unzip
: Splits the view into two iterates (keys/values).
Mutations
delete
: Removes values in the view from the source.overwrite
: Replaces values in the view from the source with a constant replacement.update
: Replace values in the view from the source with a dynamic replacement.extract
: Removes values in the view from the source and returns a new iterator with the removed values.
Operations
empty
: Determines if view contains zero values.has
: Determines if the view contains any values.contains
: Determines if the view contains a specific value.first
: Gets the first value in the view.last
: Gets the last value in the view.count
: Counts the number of values in the view.array
: Builds an array of the values in the view.set
: Builds a Set of the values in the view.object
: Builds an object of the values in the view.entries
: Builds an array of[key, value]
in the view.map
: Builds a Map of the values and keys in the view.group
: Builds an object of value arrays grouped by a value derived from each value.reduce
: Reduces the values in the view down to a single value.min
: Returns the minimum value in the view.max
: Returns the maximum value in the view.iterate
: Invokes a function for each value in the view.copy
: Copies the values in the view and returns a new iterator.changes
: Notifies you when values are added, removed, or still present on an iterator since the last time called.
Comparison Logic
The following chainable functions define how values should be compared.
numbers
: Set number comparison logic to the iterator.strings
: Set string comparison logic to the iterator.dates
: Set date comparison logic to the iterator.desc
: Reverses the comparison logic.withEquality
: Set a custom equality function.withComparator
: Set a custom comparison function.
Reset
The following function(s) allow you to change the source for iteration.
reset
: Sets a new source to iterate.
Other Functions
The following static functions exist to help iterate simple sources:
Iterate.array
: Iterates an array.Iterate.object
: Iterates the properties of an object, optionally just the properties explicitly set on the object.Iterate.tree
: Iterates trees.Iterate.linked
: Iterates linked-lists.Iterate.map
: Iterates MapsIterate.set
: Iterates SetsIterate.join
: Returns an iterator that iterates over one or more iterators.Iterate.zip
: Combines a key iterator and value iterator into one.Iterate.empty
: Iterates nothing.Iterate.entries
: Iterates an array of[key, value]
entries.Iterate.iterable
: Iterates any collection that implements iterable.Iterate.hasEntries
: Iterates any object which has theentries()
iterator.
Examples
The example is in Typescript, but iterator is available as iz.Iterate
and the function whic dynamically returns an iterator is iz.iterate
or simply iz
in JS
; // Creating an iterator;;; // each character; // anything iterable; // [key, value] tuples ; // Map<K, V>; // Set<T>;;; // ============ ITERATION ============ // Stopsource.each.withResult; // Remove// - if the source is a sequential collection, it's removed from the sequence (array, object, etc)// - if the source is a tree, it removes it from the tree including it's children// - otherwise, up to the custom sourcesource.each; // Replacesource.each; // ============ Operations ============ // These are at the end of a chain of views ; // boolean; // boolean; // boolean; // T; // T; // number; // T[]; // T[]; // Set<T>; // { [value.id]: value };; // Map<T, K>; // { [age]: T[] }; // R; // T; // T; // this // ============ Mutations ============ // These are at the end of a chain of views and they// take the values in the current iterator and affects the// underlying source. source.delete; // removes all values in iteratorsource.wherex.id.delete; // remove values without an ID source.extract; // does a delete and returns a new iterator with the removed values source.overwrite42; // replaces all values in iteratorsource.wherex > 34.overwrite12; // replace all numbers over 34 with 12 source.updatex * 2; // multiply all numbers by 2 // ============ Views ============ // These are chainable, at the end if you call an operation it performs// it only on the values in the iterator at that point. If you call// a mutation then it changes the underlying source but only on the// values in the view. source.wherex.age > 0; // values that past testsource.notx.age > 0; // values that don't pass testsource.transformx.name; // values transformed to a new typesource.reverse; // values in reversesource.excludeanotherSource; // not shared valuessource.intersectanotherSource; // shared valuessource.sortedcomparator?); // sorted by a comparatorsource.shuffletimes?); // randomly orderssource.uniqueequality?); // unique values onlysource.duplicatesonlyOnce?); // duplicate values onlysource.readonly; // all subsequent mutations are ignoredsource.keys; // just the keys (index based), delete mutation workssource.values; // just the values (index based)source.take10; // first 10 valuessource.skip5; // after first 5 valuessource.drop3; // ignore last 3source.appendanotherSource; // union of twosource.prependanotherSource; // union in reverse ordersource.gtvalue, comparator?); // all values greater than valuesource.gtevalue, comparator?); // all values greater/equal to valuesource.ltvalue, comparator?); // all values less than valuesource.ltevalue, comparator?); // all values less/equal to valuesource.forkf.where!!x.male.delete; // fork operationsource.splitx.male; // { pass, fail }source.splitx.male,: // two iteratorssource.unzip; // { keys, values }source.unzip; // two iterators // ============ Logic ============ // comparator is used for max/min/sorted/gt/gte/lt/lte// also will set withEquality if not specifiedsource.withComparatornumber; // equality check used for contains/exclude/intersect/unique/duplicatessource.withEqualityboolean; // Pre-defined logicsource.numbersascending?, nullsFirst?); // number logicsource.stringssensitive?, ascending?, nullsFirst?); // string logicsource.datesequalityTimespan?, utc?, ascending?, nullsFirst?); // date logicsource.desc; // reverse comparison logic // ============ Reset ============ source.reset; // ============ Examples ============ // Views ending with an operation or mutation. source.duplicates.has; // has duplicates?source.duplicates.delete; // remove duplicatessource.wherex.age < 18.extract; // remove < 18yosource.sorted.skip5.take10.array; // sort, get 5->15 as array // Map to a new iterator, but support replacementsource.transform // transforms values to new type value.name, // if replace is called un a subsequent iteration, how do we take the transformed value and apply it back to the original value? .each; // Iterate with a callbacksource.each; // ============ Linked List ============ // You can have any structure you wish const linkedIterator = Iterate.linked // get value from a nodenode.value, // get next nodenode.next, // remove the node (optional)prev.next = node.next, // replace value (optional)node.value = value, // if you want a key different than the value, specify thisnode.value.length; const head: Node<string> = ...; // for all nodes which have a value that passes the regex...// - sort them by value (asending), remove the top 5// - convert the unremoved unsorted nodes into an arraylinkedIteratorhead .where.testx .forkf.strings.sorted.take5.delete .array; // ============ Tree ============ // You create an iterator ready for nodes.const treeIterator = Iterate.tree // get a value from a nodenode.value, // get children from a node (can return an array, another iterator, undefined, or null)node.children, // if replace is called, apply the value (this is optional)node.value = value; const head: Node<string> = ... // Iterate depth-first and convert to an arrayconst depthFirstList = treeIteratorhead.array; // Iterate breadth-first and convert to an arrayconst breadthFirstList = treeIteratorhead, false.array;
Reusable Function
You can define a function which takes an iterator and performs any number of operations. You can optionally have it return a result.
// Iterate.func<T, R, A, K, S>// - T = value type// - R = function return type// - A = array of parameter types// - K = desired key type (restricts the source that can be passed to the function)// - S = desired source (type passed to function must match this type) // A function without a result. If a word contains an a, uppercase the word; // Any iterable source that has strings as values can be passed to function;fna;// a = [APPLE, bit, CAT] // A function with a result. If a word contains an a, uppercase it. Return the // number of changed words. The counting has to happen before the update// since the update would make no values pass the where condition.; ;; // 2// a = [APPLE, bit, CAT] // A function can have special paramters passed to it.// Given an array of people, I want a subset of that array given// a limit and offset.; ;;// page = at most 10 people starting at index 5
Custom Iterators
You can add your own iterators to pick up your own types. If you are not using TypeScript you can ignore and remove the types.
// Lets assume we have a type which is a [Date, number] tuple// which represents a range of dates. ; // First we create an iterator given the Range// The generic arguments for Iterate<T, K, S> represent:// - T = the value being iterated// - K = the key type// - S = the source type being iterated // Now that we have an iterator generator, if we wanted to we could // autmatically have the library detect my custom type and call my custom // iterator.; // We need to detect our custom type. s is DateRange is just syntactical sugar // Add a generator detection to the beginning of the list// It must return false if it's not a valid source.Generators.unshiftisDateRanges ? getDateIterators : false; // Now when we do this...; // We have our iterator and can do anything we want with it.; // BONUS!// If we want the iz function to return a type Iterator (like Iterate<Date, number, DateRange>)// we can add our own declaration file like this: // <types/iteratez/index.d.ts>; declare // </types/iteratez/index.d.ts> // then instead of this everywhere:; ; // Iterate<Date, number, DateRange> magic!