diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c1863f9f1..f0b07711bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,8 +6,7 @@ If this is your first time contributing to an Eclipse Foundation project, you'll - [Create an account](https://dev.eclipse.org/site_login/createaccount.php) on dev.eclipse.org - Open your [Account Settings tab](https://dev.eclipse.org/site_login/myaccount.php#open_tab_accountsettings), enter your GitHub ID and click Update Account - Read and [sign the ECA](https://dev.eclipse.org/site_login/myaccount.php#open_tab_cla) -- Your git commits must be [signed off](https://wiki.eclipse.org/Development_Resources/Contributing_via_Git#Signing_off_on_a_commit) -- Use the exact same email address for your Eclipse account, your commit author, and your commit sign-off. +- Use the exact same email address for your Eclipse account and your commit author. Issues ------ @@ -80,7 +79,6 @@ Commit messages - [Use the imperative mood][imperative-mood] as in "Fix bug" or "Add feature" rather than "Fixed bug" or "Added feature" - [Mention the GitHub issue][github-issue] when relevant - It's a good idea to follow the [advice in Pro Git](https://git-scm.com/book/ch5-2.html) -- Sign-off your commits using `git commit --signoff` or `git commit -s` for short Pull requests ------------- diff --git a/README.md b/README.md index 1158fb9cb6..64f6b96d24 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Eclipse Collections is compatible with Java 8+. Eclipse Collections is a part of * [Eclipse Collections Katas](https://github.com/eclipse/eclipse-collections-kata), a fun way to help you learn idiomatic Eclipse Collections usage. * Start Here - [Pet Kata](http://eclipse.github.io/eclipse-collections-kata/pet-kata/#/) * Continue Here - [Company Kata](http://eclipse.github.io/eclipse-collections-kata/company-kata/#/) -* [Eclipse Collections Reference Guide](https://github.com/eclipse/eclipse-collections/blob/master/docs/guide.md) and [Javadoc](https://www.eclipse.org/collections/javadoc/11.0.0/overview-summary.html) +* [Eclipse Collections Reference Guide](https://github.com/eclipse/eclipse-collections/blob/master/docs/0-RefGuide.adoc) and [Javadoc](https://www.eclipse.org/collections/javadoc/11.0.0/overview-summary.html) * [Serializing Eclipse Collections with Jackson](./docs/jackson.md) * [Articles](https://github.com/eclipse/eclipse-collections/wiki/Articles) and [Blogs](https://medium.com/tag/eclipse-collections/latest) * Some OSS projects that use Eclipse Collections diff --git a/docs/1-Iteration_Patterns.adoc b/docs/1-Iteration_Patterns.adoc index 52f7473e50..9059478e6b 100644 --- a/docs/1-Iteration_Patterns.adoc +++ b/docs/1-Iteration_Patterns.adoc @@ -627,7 +627,7 @@ ____ The _GroupBy_ pattern gathers the elements on the collection into a map-like container called a *{Multimap}*, which associates multiple values for each key. The *{Function}* is applied to each element and the result is used as the key into the *Multimap* where the element should appear as the value. -See xref:2-Collection_Containers.adoc#multimap-container[the discussion of Multimap] for examples of **groupby**. +See xref:2-Collection_Containers.adoc#multimap-container[the discussion of Multimap] for examples of *groupby*. **** ##`*groupBy(Function): Multimap*`## diff --git a/docs/3-Code_Blocks.adoc b/docs/3-Code_Blocks.adoc index 8dbb0a06df..194b45ac16 100644 --- a/docs/3-Code_Blocks.adoc +++ b/docs/3-Code_Blocks.adoc @@ -12,36 +12,47 @@ All rights reserved. = Code blocks :sectanchors: :toc: left -:toc-title: Code blocks +:toc-title: :toclevels: 3 // Javadoc links -:api-url: https://www.eclipse.org/collections/javadoc/11.0.0/org/eclipse/collections +:api-url: https://www.eclipse.org/collections/javadoc/11.0.0/org/eclipse/collections // -:Function: {api-url}/api/block/function/Function.html[Function] -:Function0: {api-url}/api/block/function/Function0.html[Function0] -:Function2: {api-url}/api/block/function/Function2.html[Function2] -:Function3: {api-url}/api/block/function/Function3.html[Function3] -:IntFunction: {api-url}/api/block/function/primitive/IntFunction.html[IntFunction] -:IntPredicate: {api-url}/api/block/predicate/primitive/IntPredicate.html[IntPredicate] -:IntProcedure: {api-url}/api/block/procedure/primitive/IntProcedure.html[IntProcedure] -:MutableMultimap: {api-url}/api/multimap/MutableSetMultimap.html[MutableMultimap] -:Predicate: {api-url}/api/block/predicate/Predicate.html[Predicate] -:Predicate2: {api-url}/api/block/predicate/Predicate2.html[Predicate2] -:Predicates: {api-url}/impl/block/factory/Predicates.html[Predicates] -:Predicates2: {api-url}/impl/block/factory/Predicates2.html[Predicates2] -:StringPredicates: {api-url}/impl/block/factory/StringPredicates.html[StringPredicates] -:IntegerPredicates: {api-url}/impl/block/factory/IntegerPredicates.html[IntegerPredicates] -:LongPredicates: {api-url}/impl/block/factory/LongPredicates.html[LongPredicates] -:Procedure: {api-url}/api/block/procedure/Procedure.html[Procedure] -:Procedure2: {api-url}/api/block/procedure/Procedure2.html[Procedure2] -:Functions: {api-url}/impl/block/factory/Functions.html[Functions] -:Functions0: {api-url}/impl/block/factory/Functions0.html[Functions0] -:Functions2: {api-url}/impl/block/factory/Functions2.html[Functions2] -:IfFunction: {api-url}/impl/block/function/IfFunction.html[IfFunction] -:CaseFunction: {api-url}/impl/block/function/CaseFunction.html[CaseFunction] -:StringFunctions: {api-url}/impl/block/factory/StringFunctions.html[StringFunctions] -:Procedures: {api-url}/impl/block/factory/Procedures.html[Procedures] -:Procedures2: {api-url}/impl/block/factory/Procedures2.html[Procedures2] +:CaseFunction: {api-url}/impl/block/function/CaseFunction.html[CaseFunction] +:CaseProcedure: {api-url}/impl/block/procedure/CaseProcedure.html[CaseProcedure] +:ChainedProcedure: {api-url}/impl/block/procedure/ChainedProcedure.html[ChainedProcedure] +:CollectionAddProcedure: {api-url}/impl/block/procedure/CollectionAddProcedure.html[CollectionAddProcedure] +:CollectionRemoveProcedure: {api-url}/impl/block/procedure/CollectionRemoveProcedure.html[CollectionRemoveProcedure] +:CountProcedure: {api-url}/impl/block/procedure/CountProcedure.html[CountProcedure] +:CounterProcedure: {api-url}/impl/block/procedure/CounterProcedure.html[CounterProcedure] +:Function0: {api-url}/api/block/function/Function0.html[Function0] +:Function2: {api-url}/api/block/function/Function2.html[Function2] +:Function3: {api-url}/api/block/function/Function3.html[Function3] +:Function: {api-url}/api/block/function/Function.html[Function] +:Functions0: {api-url}/impl/block/factory/Functions0.html[Functions0] +:Functions2: {api-url}/impl/block/factory/Functions2.html[Functions2] +:Functions: {api-url}/impl/block/factory/Functions.html[Functions] +:IfFunction: {api-url}/impl/block/function/IfFunction.html[IfFunction] +:IfProcedure: {api-url}/impl/block/procedure/IfProcedure.html[IfProcedure] +:IfProcedureWith: {api-url}/impl/block/procedure/IfProcedureWith.html[IfProcedureWith] +:IntFunction: {api-url}/api/block/function/primitive/IntFunction.html[IntFunction] +:IntPredicate: {api-url}/api/block/predicate/primitive/IntPredicate.html[IntPredicate] +:IntProcedure: {api-url}/api/block/procedure/primitive/IntProcedure.html[IntProcedure] +:IntegerPredicates: {api-url}/impl/block/factory/IntegerPredicates.html[IntegerPredicates] +:LongPredicates: {api-url}/impl/block/factory/LongPredicates.html[LongPredicates] +:MapPutProcedure: {api-url}/impl/block/procedure/MapPutProcedure.html[MapPutProcedure] +:MultimapPutProcedure: {api-url}/impl/block/procedure/MultimapPutProcedure.html[MultimapPutProcedure] +:MutableMultimap: {api-url}/api/multimap/MutableSetMultimap.html[MutableMultimap] +:ObjectIntProcedure: {api-url}/api/block/procedure/primitive/ObjectIntProcedure.html[ObjectIntProcedure] +:Predicate2: {api-url}/api/block/predicate/Predicate2.html[Predicate2] +:Predicate: {api-url}/api/block/predicate/Predicate.html[Predicate] +:Predicates2: {api-url}/impl/block/factory/Predicates2.html[Predicates2] +:Predicates: {api-url}/impl/block/factory/Predicates.html[Predicates] +:Procedure2: {api-url}/api/block/procedure/Procedure2.html[Procedure2] +:Procedure: {api-url}/api/block/procedure/Procedure.html[Procedure] +:Procedures2: {api-url}/impl/block/factory/Procedures2.html[Procedures2] +:Procedures: {api-url}/impl/block/factory/Procedures.html[Procedures] +:StringFunctions: {api-url}/impl/block/factory/StringFunctions.html[StringFunctions] +:StringPredicates: {api-url}/impl/block/factory/StringPredicates.html[StringPredicates] // end links; begin body A _code block_, in Eclipse Collections terms, is a single-abstract-method object that is passed as a parameter to an iteration method. @@ -52,30 +63,30 @@ This topic enumerates the basic code block types—the Eclipse Collections i What we call a "code block" in Eclipse Collections is roughly analogous to a _lambda expression_. The closest analog to a lambda in Java in versions prior to Java 8 is the _anonymous inner class_. -Here are two examples, one implementing *{Predicate}* using an anonymous inner class, and the other using a Java 8+ lambda expression. +Here are two examples, one implementing *{Predicate}* using a Java 8+ lambda expression, and the other using an anonymous inner class. -.*select* using an anonymous inner class +.*select* using a lambda ==== [source,java] ---- -MutableList texans = this.people.select( - new Predicate() - { - public boolean accept(Person each) - { - return each.getAddress().getState().equals("TX"); - } - }); +MutableList texans = + this.people.select( each -> each.getAddress().getState().equals("TX")); Verify.assertSize(1, texans); ---- ==== -.*select* using a lambda +.*select* using an anonymous inner class ==== [source,java] ---- -MutableList texans = - this.people.select( each -> each.getAddress().getState().equals("TX")); +MutableList texans = this.people.select( + new Predicate() + { + public boolean accept(Person each) + { + return each.getAddress().getState().equals("TX"); + } + }); Verify.assertSize(1, texans); ---- ==== @@ -107,13 +118,13 @@ Also known as a _discriminator_ or _filter,_ it is used with the filtering metho [cols=",,,,",options="header",] [%autowidth] |=== -| |Description |Arguments |Returns |Used By -|*Predicate* |Evaluates each element of a collection + - (the argument), and returns a boolean value. |One (T) |boolean |*select*, *reject*, *detect*, *anySatisfy*, *allSatisfy*, *count* -|*Predicate2* |Evaluates each element of a collection + - (the first argument); the second argument + - is a parameter passed into the *Predicate2* + - from the calling method. |Two (T,P) |boolean |*selectWith*, *rejectWith*, *detectWith*, *anySatisfyWith*, *allSatisfyWith*, *countWith* +| |Description |Arguments |Returns |Used By +|*Predicate* |Evaluates each element of a collection + + (the argument), and returns a boolean value. |One (T) |boolean |*select*, *reject*, *detect*, *anySatisfy*, *allSatisfy*, *count* +|*Predicate2* |Evaluates each element of a collection + + (the first argument); the second argument + + is a parameter passed into the *Predicate2* + + from the calling method. |Two (T,P) |boolean |*selectWith*, *rejectWith*, *detectWith*, *anySatisfyWith*, *allSatisfyWith*, *countWith* |=== The *accept* method is implemented to indicate the object passed to the method meets the criteria of this *Predicate*. @@ -124,13 +135,13 @@ Here is a *Predicate* implemented in a *select* method as an anonymous inner cla [source,java] ---- MutableList greaterThanFifty = - list.select(new Predicate() - { - public boolean accept(Integer each) - { - return each > 50; - } - }); + list.select(new Predicate() + { + public boolean accept(Integer each) + { + return each > 50; + } + }); ---- ==== @@ -151,11 +162,11 @@ MutableList selected1 = myList.select(Predicates.greaterThan(50)); [cols=",",] [%autowidth] |=== -|*{Predicates}* |Supports equal, greaterThan, lessThan, in, notIn, and, or, instanceOf, null, notNull, anySatisfy, allSatisfy, etc. -|*{Predicates2}* |Works with methods suffixed with "With," such as *selectWith*. -|*{StringPredicates}* |Supports empty, notEmpty, contains, isAlpha, isNumeric, isBlank, startsWith, endsWith, matches, etc. -|*{IntegerPredicates}* |Supports isEven, isOdd, isPositive, isNegative, isZero. -|*{LongPredicates}* |Supports isEven, isOdd, isPositive, isNegative, isZero. +|*{Predicates}* |Supports equal, greaterThan, lessThan, in, notIn, and, or, instanceOf, null, notNull, anySatisfy, allSatisfy, etc. +|*{Predicates2}* |Works with methods suffixed with "With," such as *selectWith*. +|*{StringPredicates}* |Supports empty, notEmpty, contains, isAlpha, isNumeric, isBlank, startsWith, endsWith, matches, etc. +|*{IntegerPredicates}* |Supports isEven, isOdd, isPositive, isNegative, isZero. +|*{LongPredicates}* |Supports isEven, isOdd, isPositive, isNegative, isZero. |=== == Function @@ -172,12 +183,12 @@ The *{Function}* code block in its most common usage takes each element of a col [cols=",,,,",options="header",] [%autowidth] |=== -| |Description |Arguments |Returns |Used By +| |Description |Arguments |Returns |Used By |*{Function}* + -_(transformer)_ |Evaluates each element of a collection as the argument to the code block logic and returns a computed value |One (T) |Object (V) |*collect*,*flatCollect*, *groupBy* -|*{Function0}* |Executes and returns a value (like Callable); represents deferred evaluation. |Zero |Object (V) |*getIfAbsent*, *getIfAbsentPut*, *ifPresentApply* -|*{Function2}* |Used by *injectInto* methods; takes the accumulator argument as the first argument, and the current item of the collection as the second argument. |Two (T,P) |Object (V) |*forEachEntry* *injectInto* *collectWith* -|*{Function3}* |Used by *injectIntoWith*; takes the injected argument as the first argument, the current item of the collection as the second argument, and the specified parameter for the third argument. The result of each subsequent iteration is passed in as the first argument. |Three (T,P,?) |Object (V) |*injectIntoWith* +_(transformer)_ |Evaluates each element of a collection as the argument to the code block logic and returns a computed value |One (T) |Object (V) |*collect*,*flatCollect*, *groupBy* +|*{Function0}* |Executes and returns a value (like Callable); represents deferred evaluation. |Zero |Object (V) |*getIfAbsent*, *getIfAbsentPut*, *ifPresentApply* +|*{Function2}* |Used by *injectInto* methods; takes the accumulator argument as the first argument, and the current item of the collection as the second argument. |Two (T,P) |Object (V) |*forEachEntry* *injectInto* *collectWith* +|*{Function3}* |Used by *injectIntoWith*; takes the injected argument as the first argument, the current item of the collection as the second argument, and the specified parameter for the third argument. The result of each subsequent iteration is passed in as the first argument. |Three (T,P,?) |Object (V) |*injectIntoWith* |=== ==== Other Functions @@ -195,10 +206,10 @@ _(transformer)_ |Evaluates each element of a collection as the argument to the [cols=",",] [%autowidth] |=== -|*Functions* |*getToClass*, *getToString*, *getPassThru* -|*Functions0* |*newFastList*, *newHashBag*, *newUnifiedMap*, *newUnifiedSet*, *nullValue*, *value* -|*Functions2* |*fromFunction* -|*StringFunctions* |*firstLetter*, *length*, *subString*, *toFirstChar*, *toInteger*, *toLowerCase*, *toPrimitive* [type], toUpperCase, trim, *firstLetter* +|*{Functions}* |*getToClass*, *getToString*, *getPassThru* +|*{Functions0}* |*newFastList*, *newHashBag*, *newUnifiedMap*, *newUnifiedSet*, *nullValue*, *value* +|*{Functions2}* |*fromFunction* +|*{StringFunctions}* |*firstLetter*, *length*, *subString*, *toFirstChar*, *toInteger*, *toLowerCase*, *toPrimitive* [type], toUpperCase, trim, *firstLetter* |=== @@ -211,8 +222,8 @@ A *{Procedure}* is a code block that performs an evaluation on its single argume [cols=",",] [%autowidth] |=== -|*CountProcedure* |Apply a *Predicate* to an object and increment a count if it returns true. -|*CounterProcedure* |Wrap a specified block and keeps track of the number of times it is executed. +|*{CountProcedure}* |Apply a *Predicate* to an object and increment a count if it returns true. +|*{CounterProcedure}* |Wrap a specified block and keeps track of the number of times it is executed. |=== === Control execution @@ -220,11 +231,11 @@ A *{Procedure}* is a code block that performs an evaluation on its single argume [cols=",",] [%autowidth] |=== -|*ChainedProcedure* |Chain together blocks of code to be executed in sequence; *ChainedProcedure* can chain **Procedure**s, **Function**s or *Function2s*. -|*CaseProcedure* |Create an object form of a case statement, which instead of being based on a single switch value is based on a list of discriminator or block combinations. For the first discriminator that returns true for a given value in the case statement, the corresponding block will be executed. -|*IfProcedure* |Evaluate the specified block only when a *Predicate* returns true. If the result of evaluating the *Predicate* is false, and the developer has specified that there is an *elseProcedure*, then the elseProcedure is evaluated. -|*IfProcedureWith* |Same as *IfProcedure*, but with a second argument passed from the calling iteration method. -|*ObjectIntProcedure* |Takes an int as a second argument; this is usually the index of the current element of a collection. +|*{ChainedProcedure}* |Chain together blocks of code to be executed in sequence; *ChainedProcedure* can chain **Procedure**s, **Function**s or *Function2s*. +|*{CaseProcedure}* |Create an object form of a case statement, which instead of being based on a single switch value is based on a list of discriminator or block combinations. For the first discriminator that returns true for a given value in the case statement, the corresponding block will be executed. +|*{IfProcedure}* |Evaluate the specified block only when a *Predicate* returns true. If the result of evaluating the *Predicate* is false, and the developer has specified that there is an *elseProcedure*, then the elseProcedure is evaluated. +|*{IfProcedureWith}* |Same as *IfProcedure*, but with a second argument passed from the calling iteration method. +|*{ObjectIntProcedure}* |Takes an int as a second argument; this is usually the index of the current element of a collection. |=== === Modify collections and maps @@ -232,10 +243,10 @@ A *{Procedure}* is a code block that performs an evaluation on its single argume [cols=",",] [%autowidth] |=== -|*CollectionAddProcedure* |Add elements to the specified collection when block methods are called. -|*CollectionRemoveProcedure* |Remove element from the specified collection when block methods are called. -|*MapPutProcedure* |Use a specified *Function* to calculate the key for an object and puts the object into the specified Map at the position of the calculated key. -|*MultimapPutProcedure* |Use a specified *Function* to calculate the key for an object and puts the object with the key into the specified *MutableMultimap*. +|*{CollectionAddProcedure}* |Add elements to the specified collection when block methods are called. +|*{CollectionRemoveProcedure}* |Remove element from the specified collection when block methods are called. +|*{MapPutProcedure}* |Use a specified *Function* to calculate the key for an object and puts the object into the specified Map at the position of the calculated key. +|*{MultimapPutProcedure}* |Use a specified *Function* to calculate the key for an object and puts the object with the key into the specified *MutableMultimap*. |=== === Procedure factories @@ -243,8 +254,8 @@ A *{Procedure}* is a code block that performs an evaluation on its single argume [cols=","] [%autowidth] |=== -|*Procedures* |*append, bind, caseDefault, fromObjectIntProcedure, ifElse, ifTrue, println, synchronizedEach* -|*Procedures2* |*addToCollection, fromProcedure* +|*{Procedures}* |*append, bind, caseDefault, fromObjectIntProcedure, ifElse, ifTrue, println, synchronizedEach* +|*{Procedures2}* |*addToCollection, fromProcedure* |=== [cols="3,^1,>3",] diff --git a/docs/guide.md b/docs/guide.md index 660ab64d7e..bae58fc51f 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -8,6 +8,9 @@ ~ http://www.eclipse.org/org/documents/edl-v10.php. --> # Reference Guide + +
+ - [About Eclipse Collections](#-about-eclipse-collections) - [About this guide](#-about-this-guide) - [Getting Started With Eclipse Collections](#-getting-started-with-eclipse-collections) diff --git a/eclipse-collections-code-generator/src/main/resources/api/list/primitiveList.stg b/eclipse-collections-code-generator/src/main/resources/api/list/primitiveList.stg index 0376ec35a0..c7def7b365 100644 --- a/eclipse-collections-code-generator/src/main/resources/api/list/primitiveList.stg +++ b/eclipse-collections-code-generator/src/main/resources/api/list/primitiveList.stg @@ -22,6 +22,7 @@ import org.eclipse.collections.api.block.function.primitive.IntToObjectFun import org.eclipse.collections.api.block.function.primitive.ToObjectFunction; import org.eclipse.collections.api.block.predicate.primitive.IntPredicate; import org.eclipse.collections.api.block.predicate.primitive.Predicate; +import org.eclipse.collections.api.block.procedure.primitive.Procedure; import org.eclipse.collections.api.block.procedure.primitive.Procedure; import org.eclipse.collections.api.list.ListIterable; import org.eclipse.collections.api.ordered.primitive.ReversibleIterable; @@ -33,6 +34,7 @@ import java.util.Spliterator; import java.util.stream.StreamSupport; import java.util.stream.Stream; +import java.util.Objects; /** * This file was automatically generated from template file primitiveList.stg. @@ -58,6 +60,27 @@ public interface List extends ReversibleIterable return this; } + /** + * This method iterates over two CharList instances of the same size together using the specified CharCharProcedure. + * + * @since 11.1 + */ + default void forEachInBoth(List other, Procedure procedure) + { + Objects.requireNonNull(other); + if (this.size() == other.size()) + { + this.forEachWithIndex((each, index) -> procedure.value(each, other.get(index))); + } + else + { + throw new IllegalArgumentException("Attempt to call forEachInBoth with two List instances of different sizes :" + + this.size() + + ':' + + other.size()); + } + } + /** * Returns a new List including all elements with corresponding indexes matching the specified predicate. * diff --git a/eclipse-collections-code-generator/src/main/resources/impl/list/mutable/synchronizedPrimitiveList.stg b/eclipse-collections-code-generator/src/main/resources/impl/list/mutable/synchronizedPrimitiveList.stg index d73b0680f2..6ab668490d 100644 --- a/eclipse-collections-code-generator/src/main/resources/impl/list/mutable/synchronizedPrimitiveList.stg +++ b/eclipse-collections-code-generator/src/main/resources/impl/list/mutable/synchronizedPrimitiveList.stg @@ -30,10 +30,11 @@ import org.eclipse.collections.api.block.function.primitive.ToObjectFuncti import org.eclipse.collections.api.block.function.primitive.ObjectIntToObjectFunction; import org.eclipse.collections.api.block.predicate.primitive.IntPredicate; import org.eclipse.collections.api.block.predicate.primitive.Predicate; -import org.eclipse.collections.api.block.procedure.primitive.IntProcedure; +import org.eclipse.collections.api.block.procedure.primitive.Procedure; +import org.eclipse.collections.api.block.procedure.primitive.IntProcedure; import org.eclipse.collections.api.collection.primitive.MutableCollection; import org.eclipse.collections.api.list.MutableList; -import org.eclipse.collections.api.list.primitive.List; +import org.eclipse.collections.api.list.primitive.List; import org.eclipse.collections.api.list.primitive.ImmutableList; import org.eclipse.collections.api.list.primitive.MutableList; import org.eclipse.collections.api.tuple.primitive.Pair; @@ -331,6 +332,15 @@ public class SynchronizedList return ReverseIterable.adapt(this); } + @Override + public void forEachInBoth(List other, Procedure procedure) + { + synchronized (this.getLock()) + { + this.getMutableList().forEachInBoth(other, procedure); + } + } + @Override public void forEachWithIndex(IntProcedure procedure) { diff --git a/eclipse-collections-code-generator/src/main/resources/test/list/mutable/abstractPrimitiveListTestCase.stg b/eclipse-collections-code-generator/src/main/resources/test/list/mutable/abstractPrimitiveListTestCase.stg index 7292662b00..2c960e17e5 100644 --- a/eclipse-collections-code-generator/src/main/resources/test/list/mutable/abstractPrimitiveListTestCase.stg +++ b/eclipse-collections-code-generator/src/main/resources/test/list/mutable/abstractPrimitiveListTestCase.stg @@ -479,6 +479,29 @@ public abstract class AbstractListTestCase extends AbstractMutableCo Assert.assertEquals(<(wideLiteral.(type))("9")>, sum[0]); } + /** + * @since 11.1. + */ + @Test + public void forEachInBoth() + { + MutableList list1 = this.newWith(<["3", "1"]:(literal.(type))(); separator=", ">); + MutableList list2 = this.newWith(<["7", "9"]:(literal.(type))(); separator=", ">); + MutableList\<Pair> result = Lists.mutable.empty(); + list1.forEachInBoth(list2, (one, two) -> result.add(PrimitiveTuples.pair(one, two))); + + MutableList\<Pair> expected = Lists.mutable.with( + PrimitiveTuples.pair(<["3", "7"]:(literal.(type))(); separator=", ">), + PrimitiveTuples.pair(<["1", "9"]:(literal.(type))(); separator=", ">)); + Assert.assertEquals(expected, result); + + MutableList list3 = this.newWith(<["7", "9", "1"]:(literal.(type))(); separator=", ">); + Assert.assertThrows( + IllegalArgumentException.class, + () -> list1.forEachInBoth(list3, + (one, three) -> result.add(PrimitiveTuples.pair(one, three)))); + } + /** * @since 11.1. */ diff --git a/unit-tests/src/test/java/org/eclipse/collections/impl/WordleTest.java b/unit-tests/src/test/java/org/eclipse/collections/impl/WordleTest.java index 4f240027ab..c59e1aaa0b 100644 --- a/unit-tests/src/test/java/org/eclipse/collections/impl/WordleTest.java +++ b/unit-tests/src/test/java/org/eclipse/collections/impl/WordleTest.java @@ -12,7 +12,9 @@ import org.eclipse.collections.api.bag.primitive.MutableCharBag; import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.primitive.CharLists; import org.eclipse.collections.api.list.ImmutableList; +import org.eclipse.collections.api.list.primitive.MutableCharList; import org.eclipse.collections.api.tuple.Triplet; import org.eclipse.collections.api.tuple.primitive.CharCharPair; import org.eclipse.collections.impl.factory.Strings; @@ -47,6 +49,9 @@ public class WordleTest @Test public void wordleTest() { + Verify.assertAllSatisfy( + TRIPLES, + triple -> triple.getOne().equals(new Wordle(triple.getTwo()).guessForEachInBoth(triple.getThree()))); Verify.assertAllSatisfy( TRIPLES, triple -> triple.getOne().equals(new Wordle(triple.getTwo()).guessInjectIntoIndex(triple.getThree()))); @@ -70,6 +75,27 @@ class Wordle this.string = string.toLowerCase(); } + public String guessForEachInBoth(String guess) + { + CharAdapter guessChars = Strings.asChars(guess.toLowerCase()); + CharAdapter hiddenChars = Strings.asChars(this.string); + MutableCharBag remaining = CharBags.mutable.empty(); + hiddenChars.forEachInBoth(guessChars, (h, g) -> remaining.add(h == g ? '.' : h)); + MutableCharList result = CharLists.mutable.empty(); + guessChars.forEachInBoth(hiddenChars, (g, h) -> result.add(this.guessMatch(g, h, remaining))); + return result.makeString(""); + } + + private char guessMatch(char guessChar, char hiddenChar, MutableCharBag remaining) + { + return guessChar == hiddenChar ? Character.toUpperCase(guessChar) : this.guessInDifferentPosition(guessChar, remaining); + } + + private char guessInDifferentPosition(char guessChar, MutableCharBag remaining) + { + return remaining.remove(guessChar) ? guessChar : '.'; + } + public String guessInjectIntoIndex(String guess) { CharAdapter guessChars = Strings.asChars(guess.toLowerCase()); @@ -78,9 +104,7 @@ public String guessInjectIntoIndex(String guess) hiddenChars.injectIntoWithIndex( CharBags.mutable.empty(), (bag, each, i) -> guessChars.get(i) == each ? bag : bag.with(each)); - return guessChars.collectWithIndex((each, i) -> hiddenChars.get(i) == each - ? Character.toUpperCase(each) : remaining.remove(each) ? each : '.') - .makeString(""); + return guessChars.collectWithIndex((each, i) -> this.guessMatch(each, hiddenChars.get(i), remaining)).makeString(""); } public String guessRejectWithIndex(String guess) @@ -89,9 +113,7 @@ public String guessRejectWithIndex(String guess) CharAdapter hiddenChars = Strings.asChars(this.string); MutableCharBag remaining = hiddenChars.rejectWithIndex((each, i) -> guessChars.get(i) == each, CharBags.mutable.empty()); - return guessChars.collectWithIndex((each, i) -> hiddenChars.get(i) == each - ? Character.toUpperCase(each) : remaining.remove(each) ? each : '.') - .makeString(""); + return guessChars.collectWithIndex((each, i) -> this.guessMatch(each, hiddenChars.get(i), remaining)).makeString(""); } public String guessSelectWithIndex(String guess) @@ -100,9 +122,7 @@ public String guessSelectWithIndex(String guess) CharAdapter hiddenChars = Strings.asChars(this.string); MutableCharBag remaining = hiddenChars.selectWithIndex((each, i) -> guessChars.get(i) != each, CharBags.mutable.empty()); - return guessChars.collectWithIndex((each, i) -> hiddenChars.get(i) == each - ? Character.toUpperCase(each) : remaining.remove(each) ? each : '.') - .makeString(""); + return guessChars.collectWithIndex((each, i) -> this.guessMatch(each, hiddenChars.get(i), remaining)).makeString(""); } public String guessZipCharReject(String guess) @@ -114,9 +134,7 @@ public String guessZipCharReject(String guess) .reject(pair -> pair.getOne() == pair.getTwo()) .collectChar(CharCharPair::getOne) .toBag(); - return charPairs.collectChar(pair -> pair.getOne() == pair.getTwo() - ? Character.toUpperCase(pair.getTwo()) : remaining.remove(pair.getTwo()) ? pair.getTwo() : '.') - .makeString(""); + return charPairs.collectChar(pair -> this.guessMatch(pair.getTwo(), pair.getOne(), remaining)).makeString(""); } } }