Skip to content

Commit da51442

Browse files
authored
release v0.10.0 (#76)
1 parent 05daae2 commit da51442

14 files changed

Lines changed: 728 additions & 279 deletions

File tree

README.md

Lines changed: 81 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,36 @@
2222

2323
## Summary
2424

25-
*Chainable* is intended to be a rich, `Iterable`-based alternative to Java's `Stream` and Google's *guava*, heavily relying on lambdas and command chaining, but focused on functional trees (tries), 2D maps, and other useful non-sequential data structures, in addition to sequences (chains). It is heavily inspired by the iterator pattern, functional programming, lazy evaluation and C#'s `Enumerable`. It is designed to enable writing powerful yet readable code quickly, succinctly, and performing sometimes faster than its non-lazy/non-functional equivalents.
26-
25+
*Chainables* is a set of fluent interface-style sub types of `Iterable` with a large selection of methods facilitating the use of the
26+
functional programming, the iterator pattern and lazy evaluation, intended for achieving code that is more succinct, readable, simpler to implement
27+
and sometimes faster than its non-lazy/non-functional equivalent.
28+
29+
It includes support for data structures such as:
30+
- **tree** (or trie) - (`ChainableTree`) enabling a number of lazy operations on trees defined in a functional-programming manner (including infinite trees)
31+
- **2-dimensional (2 key) map** (`Map2D`, `Map2DMultiValued`)
32+
- **list** -- see `ChainableList`
33+
- **queue** -- see `ChainableQueue`
34+
- and the `Chainable` interface itself, which is intended to be a rich, `Iterable`-based alternative to Java's `Stream` and Google's *guava*.
35+
2736
The implementation is lightweight, based on Java 8, self-contained, i.e. it has no external dependencies, so as not to contribute to any sub-dependency versioning challenges.
2837

38+
[Simple example](https://github.com/chainables/chainable/blob/7ff3056c0772b5b91a4eeaccf812b159f6611356/src/test/java/com/github/chainables/chainable/Examples.java#L30-L43)
39+
2940
```java
30-
Chainable<String> chain = Chainable
31-
.from(0, 0, 0, 2, 3, 7, 0, 1, 8, 3, 13, 14, 0, 2) // Integers
32-
.notAsLongAs(i -> i == 0) // Ignore leading sub chain of 0s
33-
.notAfter(i -> i == 13) // Stop after finding 13
34-
.whereEither( // Choose only those that...
35-
i -> i % 2 == 0, // ...are even
36-
i -> i > 6) // ...or greater than 6
37-
.transform(i -> Character.toString((char) (i + 65))); // Transform into letters
38-
39-
String text = chain.join(); // Merge into a string
40-
String textBackwards = chain.reverse().join(); // Reverse and merge into a string
41+
import static com.github.chainables.chainable.Chainable.chain;
42+
// ...
43+
44+
Chainable<String> chain =
45+
chain(0, 0, 0, 2, 3, 7, 0, 1, 8, 3, 13, 14, 0, 2) // Integers
46+
.notAsLongAs(i -> i == 0) // Ignore leading sub chain of 0s
47+
.notAfter(i -> i == 13) // Stop after finding 13
48+
.whereEither( // Choose only those that...
49+
i -> i % 2 == 0, // ...are even
50+
i -> i > 6) // ...or greater than 6
51+
.transform(i -> Character.toString((char) (i + 65))); // Transform into letters
52+
53+
String text = chain.join(); // Merge into a string
54+
String textBackwards = chain.reverse().join(); // Reverse and merge into a string
4155

4256
assertEquals("CHAIN", text);
4357
assertEquals("NIAHC", textBackwards);
@@ -61,24 +75,30 @@ Add this to your POM's `<depedencies>`:
6175
</dependency>
6276
```
6377

78+
Also, for easier access, it is a good idea to add the following static import to the Java file:
79+
80+
```java
81+
import static com.github.chainables.chainable.Chainable.chain;
82+
```
83+
6484
## Getting Started
6585

6686
A simple starting **chain** can be created using one of the factory methods on `Chainable`, such as [`from()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#from-T...-) or [`empty()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#empty-java.lang.Class-).
6787

6888
<details><summary>Example...</summary>
6989

7090
```java
71-
// From pre-defined values
72-
Chainable<String> chain = Chainable.from("a", "b", "c");
91+
// From pre-defined values
92+
Chainable<String> chain1 = chain("a", "b", "c");
7393

74-
// Empty but expecting String items
75-
Chainable<String> chain = Chainable.empty(String.class);
94+
// Empty but expecting String items
95+
Chainable<String> chain2 = chain(String.class);
7696

77-
// From an existing Iterable<Foo>
78-
Chainable<Foo> chain = Chainable.from(existingIterable);
97+
// From an existing Iterable<Foo>
98+
Chainable<Foo> chain3 = chain(existingIterable);
7999

80-
// From an existing Stream<Foo>
81-
Chainable<Foo> chain = Chainable.from(existingStream);
100+
// From an existing Stream<Foo>
101+
Chainable<Foo> chain4 = chain(existingStream);
82102
```
83103

84104
</details>
@@ -88,22 +108,21 @@ A simple **tree** can be created using the [`withRoot()`](https://www.javadoc.io
88108
<details><summary>Example...</summary>
89109

90110
```java
91-
// Example tree of String values
92-
ChainableTree<String> tree = ChainableTree.withRoot("root");
111+
// Example tree of String values
112+
ChainableTree<String> tree = ChainableTree.withRoot("root");
93113
```
94114

95115
and then child sub-trees can be assigned to it either:
96116
- as explicitly pre-defined trees or values:
97117

98118
```java
99-
// Assign explicit child subtrees
100-
tree.withChildren(
101-
ChainableTree
102-
.withRoot("1")
103-
.withChildren("1.1", 1.2"),
104-
ChainableTree
105-
.withRoot("2")
106-
.withChildren("2.1", "2.2"));
119+
tree.withChildren(
120+
ChainableTree
121+
.withRoot("1")
122+
.withChildValues("1.1", "1.2"),
123+
ChainableTree
124+
.withRoot("2")
125+
.withChildValues("2.1", "2.2"));
107126
```
108127

109128
- or dynamically, using functional programming by providing a child-extracting lambda -- see the [tree processing example](#tree-processing), or more in the [Tree Examples](#tree-examples) section.
@@ -124,13 +143,13 @@ Tightly integrated with `Chainable` chains, the functional programming-based tre
124143
- **infinite trees**, or trees of infinite depth, can be easily defined in terms of children-generating lambdas. For example, the code below defines a lazily evaluated infinite tree made of all the possible permutations of the letters *a*, *b* and *c*, where each layer of the tree consists of nodes of increasingly longer strings:
125144

126145
```java
127-
char[] alphabet = { 'a', 'b', 'c' }; // Define alphabet to take letters from
146+
char[] alphabet = { 'a', 'b', 'c' }; // Define alphabet to take letters from
128147
ChainableTree<String> permutations = ChainableTree
129-
.withRoot("") // Blank string at the root
148+
.withRoot("") // Blank string at the root
130149
.withChildValueExtractor(p -> Chainable
131-
.empty(String.class) // Start with an empty chain of strings
150+
.empty(String.class) // Start with an empty chain of strings
132151
.chainIndexed((s, i) -> p + alphabet[i.intValue()]) // Append each alphabet item to the parent
133-
.first(alphabet.length)); // Limit the children chain to the size of the alphabet
152+
.first(alphabet.length)); // Limit the children chain to the size of the alphabet
134153
```
135154

136155
If you were to begin to traverse this infinite tree, its initial few layers would look like this:
@@ -194,6 +213,8 @@ so that a subsequent chain can apply its logic to their outputs in a quasi-paral
194213

195214
- **breadth-first / depth-first traversal** - You can achieve a tree-like traversal of a chain, where children of each item extracted by the child-extracting lambda are inserted immediately ahead [`depthFirst()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#depthFirst-java.util.function.Function-) or appended to the end of the chain [`breadthFirst()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#breadthFirst-java.util.function.Function-), thereby resulting in a pre-order/depth-first or breadth-first traversal respectively.
196215

216+
- **crossing** - Using the `cross()` method, you can cross two chains to create one chain that iterates through all the pairs of the members of the two input chains, in a lazily evaluated fashion.
217+
197218
- **disjunctive filtering** - Using the [`whereEither()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#whereEither-java.util.function.Predicate...-) method, you can specify one or more filter predicates at the same time, with disjunctive (logical-OR) semantics. This means you can define specific filtering predicates for specific purposes and then just supply them all as parameters, rather than having to create yet another predicate that's an *OR* of the others.
198219

199220
- **skipping** of the leading sub-chain of items under various scenarios, e.g.:
@@ -209,7 +230,7 @@ so that a subsequent chain can apply its logic to their outputs in a quasi-paral
209230
- chainable **string joining/splitting** operations - You can get a chain of tokens or characters out of a string with `Chainable`'s [`split()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainables.html#split-java.lang.String-java.lang.String-boolean-) method, process it using various `Chainable` APIs and go back to a string using [`join()`](https://www.javadoc.io/static/com.github.chainables/chainable/0.5.2/com/github/chainables/chainable/Chainable.html#join-java.lang.String-).
210231
</details>
211232

212-
#### Two-dimensionals Maps
233+
#### Two-dimensional Maps
213234

214235
> :warning: To do
215236
@@ -250,20 +271,19 @@ Functional and design differences with streams aside, a level of interoperabilit
250271
In this example, an infinite tree is defined with a child extracting lambda that generates strings as permutations of letters from the specified alphabet (*a, b, c*) of increasingly greater length. Then, a "view" of the tree is defined, limiting its depth to 4 layers (including the empty root). Finally, it is transformed into a string listing of all the permutations:
251272

252273
```java
253-
char[] alphabet = { 'a', 'b', 'c' }; // Define alphabet to take letters from
274+
char[] alphabet = { 'a', 'b', 'c' }; // Define alphabet to take letters from
254275
ChainableTree<String> permutations = ChainableTree
255-
.withRoot("") // Blank string at the root
276+
.withRoot("") // Blank string at the root
256277
.withChildValueExtractor(p -> Chainable
257-
.empty(String.class) // Start with empty chain of strings
278+
.empty(String.class) // Start with an empty chain of strings
258279
.chainIndexed((s, i) -> p + alphabet[i.intValue()]) // Append each alphabet item to the parent
259-
.first(alphabet.length)); // Limit the children chain to the size of the alphabet
280+
.first(alphabet.length)); // Limit the children chain to the size of the alphabet
260281

261-
// Prepare a listing of the permutations
262-
String text = permutationsUptoLength3 = permutations
263-
.notBelowWhere(t -> t.value().length() >= 3) // Limit permutation length to 3 letters
264-
.breadthFirst() // Create chain from breadth-first traversal
265-
.afterFirst() // Skip the empty root
266-
.join(", ");
282+
String text = permutations
283+
.notBelowWhere(t -> t.value().length() >= 3) // Limit permutation length to 3 letters
284+
.breadthFirst() // Create chain from breadth-first traversal
285+
.afterFirst() // Skip the empty root
286+
.join(", ");
267287

268288
System.out.println(text);
269289
```
@@ -279,16 +299,12 @@ The beginning of the output text here, which lists all the permutations of *a*,
279299
In this example, each next item is the sum of the previous two preceding it in the chain:
280300

281301
```java
282-
// When
283-
String fibonacciFirst8 = Chainable
284-
.from(0l, 1l) // Starting values for Fibonacci
285-
.chain((i0, i1) -> i0 + i1) // Generate next Fibonacci number
286-
.first(8) // Take first 8 items
287-
.join(", "); // Merge into a string
288-
289-
assertEquals(
290-
"0, 1, 1, 2, 3, 5, 8, 13",
291-
fibonacciFirst8);
302+
String fibonacciFirst8 = chain(0l, 1l) // Starting values for Fibonacci
303+
.chain((i0, i1) -> i0 + i1) // Generate next Fibonacci number
304+
.first(8) // Take first 8 items
305+
.join(", "); // Merge into a string
306+
307+
assertEquals("0, 1, 1, 2, 3, 5, 8, 13", fibonacciFirst8);
292308
```
293309

294310
The flavor of the `chain()` method used above feeds the user-specified lambda with the two preceding items.
@@ -298,26 +314,26 @@ The beginning of the output text here, which lists all the permutations of *a*,
298314
In this examples, a chain of odd numbers is interleaved with a chain of even numbers to produce a chain of natural numbers:
299315

300316
```java
301-
final Chainable<Long> odds = Chainable
302-
.from(1l) // Start with 1
303-
.chain(o -> o + 2); // Generate infinite chain of odd numbers
317+
// Define infinite chain of odd numbers starting with 1
318+
final Chainable<Long> odds = chain(1l).chain(o -> o + 2);
304319

305-
final Chainable<Long> evens = Chainable
306-
.from(2l) // Start with 2
307-
.chain(o -> o + 2); // Generate infinite chain of even numbers
320+
// Define infinite chain of even numbers starting with 2
321+
final Chainable<Long> evens = chain(2l).chain(o -> o + 2);
308322

309323
String naturals = odds
310324
.interleave(evens) // Interleave odds with evens
311325
.first(10) // Take the first 10 items
312326
.join(", "); // Merge into a string
313327

314-
assertEquals(
315-
"1, 2, 3, 4, 5, 6, 7, 8, 9, 10"
316-
naturals);
328+
assertEquals("1, 2, 3, 4, 5, 6, 7, 8, 9, 10", naturals);
317329
```
318330

319331
> :triangular_flag_on_post: To do...
320332
321333
### Two-dimensional Map Examples
322334

323335
> :triangular_flag_on_post: To do...
336+
337+
### Traversing all permutations of items from two chains
338+
339+
> :triangular_flag_on_post: To do...

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<groupId>com.github.chainables</groupId>
66
<artifactId>chainable</artifactId>
7-
<version>0.9.0</version>
7+
<version>0.10.0</version>
88
<packaging>jar</packaging>
99

1010
<name>${project.groupId}:${project.artifactId}</name>

0 commit comments

Comments
 (0)