Sum of list of object fields using stream - java

I have a object
Class DummyObject() {
double first;
double second;
double third;
double fourth;
}
Class SomeObject() {
List<DummyObject> objectList;
}
Class HighestObject() {
List<SomeObject> objectList;
}
A variable of type SomeObject is given. I have to find out if sum of four field in DummyObject is not getting equal to amount X.
using for loop, It can easily be written like:
for(SomeObject someObject : hightestObject.getObjectList()) {
for(DummyObject dummyObject : someObject.getObjectList()){
if((dummyObject.first + dummyObject.second + dummyObject.third + dummyObject.fourth) != X) {
return false;
}
}
}
How can we do it using java stream ?

You could combine flatMap and anyMatch:
HighestObject h = ...;
boolean foundNotX = h.getObjectList().stream() //Stream<SomeObject>
.flatMap(so -> so.getObjectList().stream()) //Stream<DummyObject>
.mapToDouble(o -> o.first + o.second + o.third + o.fourth) //DoubleStream
.anyMatch(sum -> sum != X);
if (foundNotX) return false;
Depending on what you are after, using .allMatch(sum -> sum == X) might be more appropriate.

Try this.
return hightestObject.getObjectList().stream()
.flatMap(someObject -> someObject.getObjectList().stream())
.allMatch(dummyObject ->
dummyObject.first + dummyObject.second + dummyObject.third + dummyObject.fourth == X);

Related

How can I define mutually recursive lambda functions in Java?

I'm trying to implement L-system as functions. For example, dragon curve looks like this:
static String F(int n) {
return n == 0 ? "F" : F(n - 1) + "+" + G(n -1);
}
static String G(int n) {
return n == 0 ? "G" : F(n - 1) + "-" + G(n -1);
}
#Test
void testDragonCurveAsStaticFunction() {
assertEquals("F", F(0));
assertEquals("F+G", F(1));
assertEquals("F+G+F-G", F(2));
assertEquals("F+G+F-G+F+G-F-G", F(3));
}
I want to implement this with lambda functions. I got the following implementation by referring to recursion - Implement recursive lambda function using Java 8 - Stack Overflow.
#Test
void testDragonCurveAsLambdaFunction() {
interface IntStr { String apply(int i); }
IntStr[] f = new IntStr[2];
f[0] = n -> n == 0 ? "F" : f[0].apply(n - 1) + "+" + f[1].apply(n - 1);
f[1] = n -> n == 0 ? "G" : f[0].apply(n - 1) + "-" + f[1].apply(n - 1);
assertEquals("F", f[0].apply(0));
assertEquals("F+G", f[0].apply(1));
assertEquals("F+G+F-G", f[0].apply(2));
assertEquals("F+G+F-G+F+G-F-G", f[0].apply(3));
}
Is there a way to implement this without using an array?
But I want to create a generic L-System, so I don't want to define a new class, interface or method for the dragon curve.
I found a solution that uses Map.
#FunctionalInterface
interface IntStr {
String apply(int n);
static IntStr cond(String then, IntStr... otherwise) {
return n -> n == 0 ? then
: Stream.of(otherwise)
.map(f -> f.apply(n - 1))
.collect(Collectors.joining());
}
static IntStr constant(String string) {
return n -> string;
}
static IntStr call(Map<String, IntStr> map, String functionName) {
return n -> map.get(functionName).apply(n);
}
}
and
#Test
void testDragonCurveAsLambda() {
Map<String, IntStr> map = new HashMap<>();
map.put("F", IntStr.cond("F",
IntStr.call(map, "F"),
IntStr.constant("+"),
IntStr.call(map, "G")));
map.put("G", IntStr.cond("G",
IntStr.call(map, "F"),
IntStr.constant("-"),
IntStr.call(map, "G")));
IntStr f = map.get("F");
assertEquals("F", f.apply(0));
assertEquals("F+G", f.apply(1));
assertEquals("F+G+F-G", f.apply(2));
assertEquals("F+G+F-G+F+G-F-G", f.apply(3));
}
I tried implementing it using a class combining two IntStr fields set via constructor or setters:
interface IntStr {
String apply(Integer i);
}
class Recursive {
IntStr other;
IntStr curr;
public Recursive() {}
public Recursive(String p1, String s1, String p2, String s2) {
this.curr = n -> n == 0 ? p1 : curr.apply(n - 1) + s1 + other.apply(n - 1);
this.other = n -> n == 0 ? p2 : curr.apply(n - 1) + s2 + other.apply(n - 1);
}
public void setCurr(String p, String s) {
this.curr = n -> n == 0 ? p : curr.apply(n - 1) + s + other.apply(n - 1);
}
public void setOther(String p, String s) {
this.other = n -> n == 0 ? p : curr.apply(n - 1) + s + other.apply(n - 1);
}
}
Then the following code succeeded:
void testDragonCurveAsLambdaFunction() {
Recursive f1 = new Recursive("F", "+", "G", "-");
// or using setters
// f1.setCurr("F", "+");
// f1.setOther("G", "-");
assertEquals("F", f1.curr.apply(0));
assertEquals("F+G", f1.curr.apply(1));
assertEquals("F+G+F-G", f1.curr.apply(2));
assertEquals("F+G+F-G+F+G-F-G", f1.curr.apply(3));
}
An example using AtomicReference as a container for IntStr reference without creating Recursive class:
void testDragonCurveAsLambdaFunction() {
AtomicReference<IntStr>
curr = new AtomicReference<>(),
other = new AtomicReference<>();
curr.set(n -> n == 0 ? "F" : curr.get().apply(n - 1) + "+" + other.get().apply(n - 1));
other.set(n -> n == 0 ? "G" : curr.get().apply(n - 1) + "-" + other.get().apply(n - 1));
assertEquals("F", curr.get().apply(0));
assertEquals("F+G", curr.get().apply(1));
assertEquals("F+G+F-G", curr.get().apply(2));
assertEquals("F+G+F-G+F+G-F-G", curr.get().apply(3));
}

Trying to update a CompletableFuture variable but get error : local variables referenced from a lambda expression must be final or effectively final

public CompletableFuture<String> description() {
CompletableFuture<String> result = CompletableFuture
.supplyAsync(() -> "Search for: " + this.stop + " <-> " + name + ":\n")
.thenApply(x -> x += "From " + this.stop + "\n");
CompletableFuture<Void> temp = services.thenAccept(x -> {
for (BusService service : x.keySet()) {
CompletableFuture<Set<BusStop>> stops = x.get(service);
result = result.thenApply(y -> y += describeService(service, stops));
}
});
return result;
}
public CompletableFuture<String> describeService(BusService service,
CompletableFuture<Set<BusStop>> stops) {
return stops.thenApply(x -> {
if (x.isEmpty()) {
return "";
}
return x.stream()
.filter(stop -> stop != this.stop)
.reduce("- Can take " + service + " to:\n",
(str, stop) -> str += " - " + stop + "\n",
(str1, str2) -> str1 + str2);
});
}
I was trying to update the result in the forloop in description(), since result.thenApply() results in a new CompletableFuture instance, I need to reassign it to a new variable in order to update result, but i am not very sure how
You don't need to reassign it to a new variable, and you shouldn't. Combine the futures instead.
return services.thenCombine(result, (x, y) -> {
for (BusService service : x.keySet()) {
CompletableFuture<Set<BusStop>> stops = x.get(service);
y += describeService(service, stops);
}
return y;
});

Regular Expression Union and subtracion for numeric

I am trying to have a union of regular expression and subtraction,I am able work range only like. String regex = "[1-3[5-7]]"; but need different type of numbers with range and at the same time union also like String regex = "\b([1-9]|[1-4][0-9]|5[0-5]&&[191])\b"; In this line am able to match 1 to 55 and also match 191.it is not working.Can any one give the suggestion where the problem getting. I tried for numeric range like below.
public class NumericRangeRegex {
public String baseRange(String num, boolean up, boolean leading1) {
char c = num.charAt(0);
char low = up ? c : leading1 ? '1' : '0';
char high = up ? '9' : c;
if (num.length() == 1)
return charClass(low, high);
String re = c + "(" + baseRange(num.substring(1), up, false) + ")";
if (up) low++; else high--;
if (low <= high)
re += "|" + charClass(low, high) + nDigits(num.length() - 1);
return re;
}
private String charClass(char b, char e) {
return String.format(b==e ? "%c" : e-b>1 ? "[%c-%c]" : "[%c%c]", b, e);
}
private String nDigits(int n) {
return nDigits(n, n);
}
private String nDigits(int n, int m) {
return "[0-9]" + String.format(n==m ? n==1 ? "":"{%d}":"{%d,%d}", n, m);
}
private String eqLengths(String from, String to) {
char fc = from.charAt(0), tc = to.charAt(0);
if (from.length() == 1 && to.length() == 1)
return charClass(fc, tc);
if (fc == tc)
return fc + "("+rangeRegex(from.substring(1), to.substring(1))+")";
String re = fc + "(" + baseRange(from.substring(1), true, false) + ")|"
+ tc + "(" + baseRange(to.substring(1), false, false) + ")";
if (++fc <= --tc)
re += "|" + charClass(fc, tc) + nDigits(from.length() - 1);
return re;
}
private String nonEqLengths(String from, String to) {
String re = baseRange(from,true,false) + "|" + baseRange(to,false,true);
if (to.length() - from.length() > 1)
re += "|[1-9]" + nDigits(from.length(), to.length() - 2);
return re;
}
public String run(int n, int m) {
return "\\b0*?("+ rangeRegex("" + n, "" + m) +")\\b";
}
public String rangeRegex(String n, String m) {
return n.length() == m.length() ? eqLengths(n, m) : nonEqLengths(n, m);
}
}
I think you are on the wrong track. You should simply extract and parse the numeric values and do the calculation in your regular programming language, as recommended by Patrick.
You can still create a wrapper class that helps to check numeric ranges using a simple function like
public static boolean between(int i, int minValueInclusive, int maxValueInclusive) {
return (i >= minValueInclusive && i <= maxValueInclusive);
}
or use commons.lang.Range:
Range<Integer> myRange = Range.between(1, 55);
if (myRange.contains(value)){
// do something
}
Based on conditions Ill try for union and subtraction is `^(?!250)0*?([0-9]|2(5([0-5])|[0-4][0-9])|1[0-9]{2}|[1-9][0-9]|2000)$. In this we are matching 1 to 255 range and 2000 numeric number(union) and for negate 250(subtraction).It's working fine.

Lambda Expression to find sum

I have a class as below:
public class Class2 {
private final Integer x;
private final Integer y;
public Class2(final Integer x, Integer y) {
this.x = x;
this.y = y;
}
public Integer getX() {
return x;
}
public Integer getY() {
return y;
}
}
I have a Map object like below:
Map<MyEnum , List<Class2>> mapX
I want to find the sum of x & y members of the Class2 instances in the List instance which is the value item in the above map. I want to use lambda expressions
I have come up with the following incomplete lambda. Thanks in advance.
mapX.entrySet().forEach(entry -> {
System.out.println("MapX-Key : " + entry.getKey() + "\nMapX-Value : "
+ entry.getValue().stream().collect(Collectors.summingInt(???)));
});
Not quite sure about what you're asking but one of these should help:
// Using Class2
Map<MyEnum , List<Class2>> mapX = null;
mapX.entrySet().forEach(entry -> {
System.out.println("MapX-Key : " + entry.getKey() + "\nMapX-Value : "
+ entry.getValue().stream()
.collect(Collectors.summingInt(x -> x.getX() + x.getY())));
});
// Values from Class2 via Class1
Map<MyEnum , List<Class1>> map1 = null;
map1.entrySet().forEach(entry -> {
System.out.println("MapX-Key : " + entry.getKey() + "\nMapX-Value : "
+ entry.getValue().stream()
.collect(Collectors.summingInt(x -> x.getClass2().getX() + x.getClass2().getY())));
});
You can go this way :
mapX.entrySet().stream()
.map(entry -> "MapX-Key : " + entry.getKey()
+ "\nMapX-Value : "
+ entry.getValue().stream().mapToInt(e -> e.getX() + e.getY()))
.forEach(System.out::println);
This will iterate over each Entry, then (map) create a String with the key, and then the sum of x and y, and at the end print them

Is there a Java library that will create a number range from a list of numbers?

I am creating a table of contents, and what I have is a Map of product numbers to pages. So an entry might look like this:
ABC123 => [59, 58, 57, 19, 36, 15, 33, 34, 13, 39, 11, 37, 38, 21, 20, 40, 63, 60, 45, 46, 22, 23, 24, 26, 3, 2, 10, 1, 7, 6, 5, 4, 8]
What I want to get from this is:
1-8,10,11,13,15,19-24,26,33,34,36-38,40,45,46,57-60
I can code this of course, but I figured that someone else has already solved this problem. My Googling has yielded naught.
I appreciate any help you can offer, as always!
You could collect the numbers into a sorted set and then iterate over the numbers.
Quick and dirty example:
SortedSet<Integer> numbers = new TreeSet<Integer>();
numbers.add( 1 );
numbers.add( 2 );
numbers.add( 3 );
numbers.add( 6 );
numbers.add( 7 );
numbers.add( 10 );
Integer start = null;
Integer end = null;
for( Integer num : numbers ) {
//initialize
if( start == null || end == null ) {
start = num;
end = num;
}
//next number in range
else if( end.equals( num - 1 ) ) {
end = num;
}
//there's a gap
else {
//range length 1
if( start.equals( end )) {
System.out.print(start + ",");
}
//range length 2
else if ( start.equals( end - 1 )) {
System.out.print(start + "," + end + ",");
}
//range lenth 2+
else {
System.out.print(start + "-" + end + ",");
}
start = num;
end = num;
}
}
if( start.equals( end )) {
System.out.print(start);
}
else if ( start.equals( end - 1 )) {
System.out.print(start + "," + end );
}
else {
System.out.print(start + "-" + end);
}
Yields: 1-3,6,7,10
Apache Commons has the IntRange type that you can use. Unfortunately I didn't find a good corresponding set of utilities to create them. Here's the basic approach you could use:
//create a list of 1-integer ranges
List<IntRange> ranges = new LinkedList<IntRange>();
for ( int pageNum : pageNums ) {
ranges.add(new IntRange(pageNum));
}
//sort the ranges
Collections.sort(ranges, new Comparator<IntRange>() {
public int compare(IntRange a, IntRange b) {
return Integer.valueOf(a.getMinimumInteger()).compareTo(b.getMinimumInteger());
}
});
List<IntRange> output = new ArrayList<IntRange>();
if ( ranges.isEmpty() ) {
return output;
}
//collapse consecutive ranges
IntRange range = ranges.remove(0);
while ( !ranges.isEmpty() ) {
IntRange nextRange = ranges.remove(0);
if ( range.getMaximumInteger() == nextRange.getMinimumInteger() - 1 ) {
range = new IntRange(range.getMinimumInteger(), nextRange.getMaximumInteger());
} else {
output.add(range);
range = nextRange;
}
}
output.add(range);
Alternatively you could skip the first step and create the ranges directly from the sorted list of page numbers.
Edit: A better description:
I had to deal with something similar to support a sorted collection of finite ranges, I used a mix of Google's Guava Range class and binary search to insert the element at the corresponding range or create a new singleton Range (A range with 1 element), eventually with more inserts the ranges have chances of expanding (Or shrinking/splitting in case of removal), removal is pretty fast because locating the corresponding range where the element is uses a binary search:
import com.google.common.collect.DiscreteDomains;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
import java.util.Collection;
import java.util.List;
public class IntRangeCollection
{
private int factor=10;
private List<Range<Integer>> rangeList=null;
public IntRangeCollection()
{
rangeList=Lists.newArrayListWithExpectedSize(1000);
}
public IntRangeCollection(final int size)
{
rangeList=Lists.newArrayListWithExpectedSize(size);
}
public IntRangeCollection(final int size, final int factor)
{
rangeList=Lists.newArrayListWithExpectedSize(size);
this.factor=factor;
}
protected IntRangeCollection(final List<Range<Integer>> rangeList)
{
this.rangeList=rangeList;
}
public static IntRangeCollection buildIntRangesCollectionFromArrays(final List<Integer[]> arrays)
{
final List<Range<Integer>> rangeList=Lists.newArrayListWithCapacity(arrays.size());
for(Integer[] range : arrays){
rangeList.add(range.length == 1 ? Ranges.singleton(range[0]) : Ranges.closed(range[0], range[1]));
}
return new IntRangeCollection(rangeList);
}
public boolean addElements(final Collection<Integer> elements)
{
boolean modified=false;
for(Integer element : elements){
modified=addElement(element) || modified;
}
return modified;
}
public boolean removeElements(final Collection<Integer> elements)
{
boolean modified=false;
for(Integer element : elements){
modified=removeElement(element) || modified;
}
return modified;
}
public boolean addElement(final Integer element)
{
final Range<Integer> elementRange=Ranges.singleton(element);
if(rangeList.isEmpty()){
rangeList.add(elementRange);
} else{
int
start=0, mid=0,
end=rangeList.size() - 1;
Range<Integer> midRange=null;
while(start<=end){
mid=(start + end) / 2;
midRange=rangeList.get(mid);
if(midRange.contains(element)){
return false;
} else if(testLinkable(midRange, element)){
rangeList.set(mid, midRange.span(elementRange));
if(mid>0){
final Range<Integer> a=rangeList.get(mid - 1);
if(testLinkable(a, midRange)){
rangeList.set(mid - 1, a.span(midRange));
rangeList.remove(mid);
mid--;
}
}
if(mid<rangeList.size() - 1){
final Range<Integer> b=rangeList.get(mid + 1);
if(testLinkable(midRange, b)){
rangeList.set(mid, midRange.span(b));
rangeList.remove(mid + 1);
}
}
return true;
} else if(midRange.lowerEndpoint().compareTo(element)<0){
start=mid + 1;
} else{
end=mid - 1;
}
}
//noinspection ConstantConditions
rangeList.add(midRange.lowerEndpoint().compareTo(element)<0 ? mid + 1 : mid, elementRange);
}
return true;
}
public boolean removeElement(final Integer element)
{
final Range<Integer> elementRange=Ranges.singleton(element);
if(rangeList.isEmpty()){
rangeList.add(elementRange);
} else{
int
start=0, mid,
end=rangeList.size() - 1;
while(start<=end){
mid=(start + end) / 2;
final Range<Integer> midRange=rangeList.get(mid);
if(midRange.contains(element)){
final Integer
lower=midRange.lowerEndpoint(),
upper=midRange.upperEndpoint();
if(lower.equals(upper)){
rangeList.remove(mid);
} else if(lower.equals(element)){
rangeList.set(mid, Ranges.closed(element + 1, upper));
} else if(upper.equals(element)){
rangeList.set(mid, Ranges.closed(lower, element - 1));
} else{
rangeList.set(mid, Ranges.closed(element + 1, upper));
rangeList.add(mid, Ranges.closed(lower, element - 1));
}
return true;
} else if(midRange.lowerEndpoint().compareTo(element)<0){
start=mid + 1;
} else{
end=mid - 1;
}
}
}
return false;
}
public List<Integer> getElementsAsList()
{
final List<Integer> result=Lists.newArrayListWithExpectedSize(rangeList.size() * factor);
for(Range<Integer> range : rangeList){
result.addAll(range.asSet(DiscreteDomains.integers()));
}
return result;
}
public List<Integer[]> getRangesAsArray()
{
final List<Integer[]> result=Lists.newArrayListWithCapacity(rangeList.size());
for(Range<Integer> range : rangeList){
final Integer
lower=range.lowerEndpoint(),
upper=range.upperEndpoint();
result.add(lower.equals(upper) ? new Integer[]{lower} : new Integer[]{lower,upper});
}
return result;
}
public int getRangesCount()
{
return rangeList.size();
}
private boolean testLinkable(final Range<Integer> range, final Integer element)
{
return Ranges.closed(range.lowerEndpoint() - 1, range.upperEndpoint() + 1).contains(element);
}
private boolean testLinkable(final Range<Integer> a, final Range<Integer> b)
{
return Ranges.closed(a.lowerEndpoint() - 1, a.upperEndpoint() + 1).isConnected(b);
}
#Override
public String toString()
{
return "IntRangeCollection{" +
"rangeList=" + rangeList +
'}';
}
public static void main(String[] args)
{
final int MAX_NUMBER=1000;
final long startMillis=System.currentTimeMillis();
final IntRangeCollection ranges=new IntRangeCollection();
for(int i=0; i<MAX_NUMBER; i++){
//noinspection UnsecureRandomNumberGeneration
ranges.addElement((int) (Math.random() * MAX_NUMBER));
}
System.out.println(MAX_NUMBER + " contained in " + ranges.rangeList.size() + " ranges done in " + (System.currentTimeMillis() - startMillis) + "ms");
System.out.println(ranges);
for(int i=0; i<MAX_NUMBER / 4; i++){
//noinspection UnsecureRandomNumberGeneration
ranges.removeElement((int) (Math.random() * MAX_NUMBER));
}
System.out.println(MAX_NUMBER + " contained in " + ranges.rangeList.size() + " ranges done in " + (System.currentTimeMillis() - startMillis) + "ms");
System.out.println(ranges);
}
}
You can use Arrays.sort() and find neighbouring duplicates/ranges. However I suspect TreeSet may be simpler to use.
This is a good example, it shows a simple way to accomplish this.

Categories

Resources