I have these two classes
public class Iris_Setosa {
private double sepal_length;
private double sepal_width;
private double petal_length;
private double petal_width;
//Constractor
public Iris_Setosa(double s_length,double s_width,double p_length,double p_width)
{
this.sepal_length=s_length;
this.sepal_width=s_width;
this.petal_length=p_length;
this.petal_width=p_width;
}
public double sepal_length()
{
return this.sepal_length;
}
public double sepal_width()
{
return this.sepal_width;
}
public double petal_length()
{
return this.petal_length;
}
public double petal_width()
{
return this.petal_width;
}
}
public class Iris_Versicolour {
private double sepal_length;
private double sepal_width;
private double petal_length;
private double petal_width;
//Constractor
public Iris_Versicolour(double s_length,double s_width,double p_length,double p_width)
{
this.sepal_length=s_length;
this.sepal_width=s_width;
this.petal_length=p_length;
this.petal_width=p_width;
}
public double sepal_length()
{
return this.sepal_length;
}
public double sepal_width()
{
return this.sepal_width;
}
public double petal_length()
{
return this.petal_length;
}
public double petal_width()
{
return this.petal_width;
}
}
I defined two vectors and set data:
Vector <Iris_Setosa> I_Setosa = new Vector <Iris_Setosa>();
Vector <Iris_Versicolour> I_Versicolour = new Vector <Iris_Versicolouלr>();
//data
I_Setosa.add(new Iris_Setosa (4.6,3.4,1.4,0.3));
I_Setosa.add(new Iris_Setosa (5.4,3.9,1.7,0.4));
I_Versicolour.add(new Iris_Versicolour(6.4,3.2,4.5,1.5));
I_Versicolour.add(new Iris_Versicolour(6.9,3.1,4.9,1.5));
.......
How do we classify these two vectors together, in order to be treated as points in space?
So now you have a new sample, s = [4.7, 3.3, 1.5, 0.5]
A first quick and dirty method would be 1NN (K Nearest Neighbors with K=1). In this case you would compute the euclidean distance between s and each of your four points.
You would find that four your four cases you have the distances 5.93, 6.40, 6.94, and 7.12. In this case you choose the first training sample since it is closest, leading to a prediction of I_Setosa. More specifically, it was most similar to Iris_Setosa (4.6,3.4,1.4,0.3)
Hope this helps
Related
Question Summary
Is there any way of updating the probabilities within an existing instance of the class EnumeratedIntegerDistribution without creating an entirely new instance?
Background
I'm trying to implement a simplified Q-learning style demonstration using an android phone. I need to update the probabilities for each item with each loop through the learning process. Currently I am unable to find any method accessible from my instance of enumeratedIntegerDistribution that will let me reset|update|modify these probabilities. Therefore, the only way I can see to do this is to create a new instance of EnumeratedIntegerDistribution within each loop. Keeping in mind that each of these loops is only 20ms long, it is my understanding that this would be terribly memory inefficient compared to creating one instance and updating the values within the existing instance. Is there no standard set-style methods to update these probabilities? If not, is there a recommended workaround (i.e. using a different class, making my own class, overriding something to make it accessible, etc.?)
A follow up would be whether or not this question is a moot effort. Would the compiled code actually be any more/less efficient by trying to avoid this new instance every loop? (I'm not knowledgeable enough to know how compilers would handle such things).
Code
A minimal example below:
package com.example.mypackage.learning;
import android.app.Activity;
import android.os.Bundle;
import org.apache.commons.math3.distribution.EnumeratedIntegerDistribution;
public class Qlearning extends Activity {
private int selectedAction;
private int[] actions = {0, 1, 2};
private double[] weights = {1.0, 1.0, 1.0};
private double[] qValues = {1.0, 1.0, 1.0};
private double qValuesSum;
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
private final double alpha = 0.001;
int action;
double reward;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(true){
action = determineAction();
reward = determineReward();
learn(action, reward);
}
}
public void learn(int action, double reward) {
qValues[selectedAction] = (alpha * reward) + ((1.0 - alpha) * qValues[selectedAction]);
qValuesSum = 0;
for (int i = 0; i < qValues.length; i++){
qValuesSum += Math.exp(qValues[i]);
}
weights[selectedAction] = Math.exp(qValues[selectedAction]) / qValuesSum;
// *** This seems inefficient ***
EnumeratedIntegerDistribution enumeratedIntegerDistribution = new EnumeratedIntegerDistribution(actions, weights);
}
}
Please don't focus on the absence of the determineAction() or determineReward() methods, as this is simply a minimal example. You could easily just sub in fixed values there (e.g. 1, and 1.5) if you wanted a working example.
Also, I'm well aware of the infinite while loop that would be troublesome for a GUI, but again, just trying to reduce the code I have to show here to get the point across.
Edit:
In response to a comment I'm posting what I had for a similar class below. Note I haven't used this in over a year and things may be broken. Just posting for reference:
public class ActionDistribution{
private double reward = 0;
private double[] weights = {0.34, 0.34, 0.34};
private double[] qValues = {0.1, 0.1, 0.1};
private double learningRate = 0.1;
private double temperature = 1.0;
private int selectedAction;
public ActionDistribution(){}
public ActionDistribution(double[] weights, double[] qValues, double learningRate, double temperature){
this.weights = weights;
this.qValues = qValues;
this.learningRate = learningRate;
this.temperature = temperature;
}
public int actionSelect(){
double sumOfWeights = 0;
for (double weight: weights){
sumOfWeights = sumOfWeights + weight;
}
double randNum = Math.random() * sumOfWeights;
double selector = 0;
int iterator = -1;
while (selector < randNum){
try {
iterator++;
selector = selector + weights[iterator];
}catch (ArrayIndexOutOfBoundsException e){
Log.e("abcvlib", "weight index bound exceeded. randNum was greater than the sum of all weights. This can happen if the sum of all weights is less than 1.");
}
}
// Assigning this as a read-only value to pass between threads.
this.selectedAction = iterator;
// represents the action to be selected
return iterator;
}
public double[] getWeights(){
return weights;
}
public double[] getqValues(){
return qValues;
}
public double getQValue(int action){
return qValues[action];
}
public double getTemperature(){
return temperature;
}
public int getSelectedAction() {
return selectedAction;
}
public void setWeights(double[] weights) {
this.weights = weights;
}
public void setQValue(int action, double qValue) {
this.qValues[action] = qValue;
}
public void updateValues(double reward, int action){
double qValuePrev = getQValue(action);
// update qValues due to current reward
setQValue(action,(learningRate * reward) + ((1.0 - learningRate) * qValuePrev));
// update weights from new qValues
double qValuesSum = 0;
for (double qValue : getqValues()) {
qValuesSum += Math.exp(temperature * qValue);
}
// update weights
for (int i = 0; i < getWeights().length; i++){
getWeights()[i] = Math.exp(temperature * getqValues()[i]) / qValuesSum;
}
}
public double getReward() {
return reward;
}
public void setReward(double reward) {
this.reward = reward;
}
}
Unfortunately it is not possible to update the existing EnumeratedIntegerDistribution. I have had similar issue in the past and I ended up re-creating the instance everytime I need to update the chances.
I won't worry too much about the memory allocations as those will be short-lived objects. These are micro-optimisations you should not worry about.
In my project I did implement a cleaner way with interfaces to create instances of these EnumeratedDistribution class.
This is not the direct answer but might guide you in the right direction.
public class DistributedProbabilityGeneratorBuilder<T extends DistributedProbabilityGeneratorBuilder.ProbableItem> {
private static final DistributedProbabilityGenerator EMPTY = () -> {
throw new UnsupportedOperationException("Not supported");
};
private final Map<Integer, T> distribution = new HashMap<>();
private DistributedProbabilityGeneratorBuilder() {
}
public static <T extends ProbableItem> DistributedProbabilityGeneratorBuilder<T> newBuilder() {
return new DistributedProbabilityGeneratorBuilder<>();
}
public DistributedProbabilityGenerator build() {
return build(ProbableItem::getChances);
}
/**
* Returns a new instance of probability generator at every call.
* #param chanceChangeFunction - Function to modify existing chances
*/
public DistributedProbabilityGenerator build(Function<T, Double> chanceChangeFunction) {
if (distribution.isEmpty()) {
return EMPTY;
} else {
return new NonEmptyProbabilityGenerator(createPairList(chanceChangeFunction));
}
}
private List<Pair<Integer, Double>> createPairList(Function<T, Double> chanceChangeFunction) {
return distribution.entrySet().stream()
.map(entry -> Pair.create(entry.getKey(), chanceChangeFunction.apply(entry.getValue())))
.collect(Collectors.toList());
}
public DistributedProbabilityGeneratorBuilder<T> add(int id, T item) {
if (distribution.containsKey(id)) {
throw new IllegalArgumentException("Id " + id + " already present.");
}
this.distribution.put(id, item);
return this;
}
public interface ProbableItem {
double getChances();
}
public interface DistributedProbabilityGenerator {
int generateId();
}
public static class NonEmptyProbabilityGenerator implements DistributedProbabilityGenerator {
private final EnumeratedDistribution<Integer> enumeratedDistribution;
NonEmptyProbabilityGenerator(List<Pair<Integer, Double>> pairs) {
this.enumeratedDistribution = new EnumeratedDistribution<>(pairs);
}
#Override
public int generateId() {
return enumeratedDistribution.sample();
}
}
public static ProbableItem ofDouble(double chances) {
return () -> chances;
}
}
Note - I am using EnumeratedDistribution<Integer>. You can easily change it to be EnumuratedIntegerDistribution.
The way I use the above class is as follows.
DistributedProbabilityGenerator distributedProbabilityGenerator = DistributedProbabilityGeneratorBuilder.newBuilder()
.add(0, ofDouble(10))
.add(1, ofDouble(45))
.add(2, ofDouble(45))
.build();
int generatedObjectId = distributedProbabilityGenerator.generateId();
Again, this is not a direct answer to your question but more of a pointer towards how you can use these classes in a better way.
After researching a little bit, I couldn't figure out how to create a obj1 distance to be able to compare with obj2. All these methods were given in assessment I had so, no chance to change logic of it. I suppose to return 3 Strings answer depending of the data. Thanks a lot in advance guys. I've attached a pease of pic.
enter image description here
public class Main {
public static void main(String[] args) {
Distance dist1 = new DistanceImplementation();
Distance obj2 = new DistanceImplementation();
dist1.setFeetAndInches(1, 8);
obj2.setFeetAndInches(3, 5);
System.out.println(dist1.getDistanceComparison(obj2));
}
}
public abstract class Distance {
protected int feet;
protected float inches;
abstract public void setFeetAndInches(int feet, float inches);
abstract public int getFeet();
abstract public float getInches();
abstract String getDistanceComparison(Distance dist2);
}
class DistanceImplementation extends Distance {
#Override
public void setFeetAndInches(int feet, float inches) {
this.feet = feet;
this.inches = inches;
}
#Override
public int getFeet() {
return this.feet;
}
#Override
public float getInches() {
return this.inches;
}
#Override
String getDistanceComparison(Distance dist2) {
// if (dist2) { ????????????
return null;
}
}
Well, after reading the assessment, I think that you can safely assume that 1 foot = 12 inches. So, in order to correctly implement the getDistanceComparison method, you could calculate the total distance in inches for both the current object and the parameter, compare them and then return the corresponding string value.
Suppose you have the following method:
private float getTotalInches() {
return (float) feet * 12.0 + inches;
}
This method returns the total inches of this DistanceImplementation instance, taking into account the feet and the inches attributes.
Please note that for the total result to be of type float, we need to first cast the feet attribute to float, so that it actually becomes of type float. Then, we multiply by 12.0 (note the .0, it's important because it indicates that the 12.0 literal value is also a float). Then, we are summing two float values, which yields a result of type float. While all this casting and convertions are not always necessary (sometimes the compiler is smart enough as to guess the correct types and preserve decimal precision), it's considred good practice to make your intentions crystal-clear, so that future developers that will maintain your code know what you have tried to accomplish.
Then, once you have this method, it would be easy to compare the total inches of both DistanceImplementation instances and return the corresponding string:
#Override
String getDistanceComparison(Distance dist2) {
float myTotalInches = getTotalInches();
float otherTotalInches = dist2.getTotalInches();
if (myTotalInches > otherTotalInches) {
// return ...
} else if (myTotalInches < otherTotalInches) {
// return ...
} else {
// return ...
}
}
Here is the solution on which I was working and it might be useful as well
package com.prog;
import java.util.Scanner;
abstract class Distance {
protected int feet;
protected float inches;
abstract public void setFeetAndInches(int feet, float inches);
abstract public int getFeet();
abstract public float getInches();
abstract String getDistanceComparison(Distance dist2);
}
public class DistanceCalculator {
private static final Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
Distance dist1 = new DistanceImplementation();
Distance dist2 = new DistanceImplementation();
int feet1 = 1;
float inches1 = (float) 2.0;
int feet2 = 3;
float inches2 = (float) 4.1;
dist1.setFeetAndInches(feet1, inches1);
dist2.setFeetAndInches(feet2, inches2);
System.out.println(dist1.getDistanceComparison(dist2));
}
}
package com.prog;
public class DistanceImplementation extends Distance {
#Override
public void setFeetAndInches(int feet, float inches) {
this.feet=(int) (feet+ (inches/12));
this.inches=inches+ (feet*12);
}
#Override
public int getFeet() {
return feet;
}
#Override
public float getInches() {
return inches;
}
#Override
String getDistanceComparison(Distance dist2) {
String ret;
int dist1a=this.getFeet();
System.out.println(dist1a);
int dist2a=dist2.getFeet();
if(dist1a > dist2a)
return "First is greater";
else if(dist1a < dist2a)
return "Second is greater";
else
return "Both are equal";
}
}
I am trying to create a method for " winning percentage " in a player class. I know I need to incorporate total wins divided by total games played, but the code is meant to be simple so I cannot use complex code. (beginner project in computer science) Any useful feedback would be great as I have spent multiple days attempting this and getting no where. By the way, ties count as half a win.
Update: Implemented the getters into the getWinningPercentage method. Also calculated everything inside the getWinningPercentage and removed the setWinningPercentage considering it was useless code. Results were as follows:
Bob
5 wins, 1 losses, 2 ties
Winning percentage = 0.75
public class Player
{
private int numWins = 0;
private int numTies = 0;
private int numLosses = 0;
private String name;
public void setWins(int w)
{
numWins = w;
}
public int getWins()
{
return numWins;
}
public void setTies(int t)
{
numTies = t;
}
public int getTies()
{
return numTies;
}
public void setLosses(int L)
{
numLosses = L;
}
public int getLosses()
{
return numLosses;
}
public void setName(String n)
{
name = n;
}
public String getName()
{
return name;
}
public void incrementWins()
}
numWins++;
}
public void incrementTies()
{
numTies++;
}
public void incrementLosses()
{
numLosses++;
}
public double getWinningPercentage()
{
double totalGames = getWins() + getTies() + getLosses();
double totalWins = getWins() + (getTies() / 2.0);
double winningPercentage = (totalWins / totalGames);
return winningPercentage;
}
}
The winning percentage should be a calculated property, not a field, and not have a setter method. Instead there should only be a "getter" (public double getWinningPercentage()) method and you should calculate and return this value from within the method itself from the other fields that your class already has.
We should leave it up to you to create this method and formula yourself.
I was looking for some good patterns to have possibility to express distance in different units. I found Martin Fowler article about quantities and I programmed something like:
Here is Distance class ( I think it is not necessery to make it abstract ):
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double factor = this.mUnit.getMetresFactor()/unit.getMetresFactor();
double newValue = this.mValue * factor;
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
It looks very simple. Conversion toUnit is based on DistanceUnit method getMetresFactor. Each Unit class implements DistanceUnit interface and has method getMetresFactor() like:
public interface DistanceUnit {
double getMetresFactor();
}
public class Inch implements DistanceUnit {
#Override
public double getMetresFactor() {
return 0.0254;
}
}
public class Kilometer implements DistanceUnit {
#Override
public double getMetresFactor() {
return 1000.0;
}
}
And the usage is for example:
Distance inches = new Distance(300.0, new Inch());
Distance kilometres = inches.toUnit(new Kilometres());
So it returns the correct value.
Is it good way to store distance in this way? Maybe you know some weaknesses of this approach. Maybe is a good idea to use here a FactoryMethod pattern to construct distance based on unit shortcut like "m" for meter. I think about the amount of classes if I would have a lot of units... Is it good idea to have factory which return factor of meters based on unit name? There will be no classes for units then?
Hm, i would use enum instead of DistanceUnit classes, because there is no different instances of them.
You can set a value to enum like here
and then call enum.getValue() instead of unit.getMetresFactor().
Also it is a little bit confusing, is the mValue value in meters or in DistanceUnit's, if in meters, you must have
double factor = unit.getMetresFactor();
there
Ok and now with any convertion function support:
import java.util.HashMap;
import java.util.Map;
public abstract class MeasureConverter {
public abstract double valueToBasic(double value);
public abstract double basictoValue(double basic);
/**
*
*/
public static Map<String, MeasureConverter> converters;
public static Map<String, MeasureConverter> getConverters() {
if (converters == null) {
converters = new HashMap<String, MeasureConverter>();
converters.put("kilo", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1000;
}
#Override
public double basictoValue(double basic) {
return basic / 0.001;
}
});
// taking the basic temperature value in kelvines
converters.put("kelvine", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value;
}
#Override
public double basictoValue(double basic) {
return basic;
}
});
converters.put("celsius", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value + 273.15;
}
#Override
public double basictoValue(double basic) {
return basic - 273.15;
}
});
converters.put("faren", new MeasureConverter() {
#Override
public double valueToBasic(double value) {
return value * 1.8 - 459.67 ; // or whatever is there?
}
#Override
public double basictoValue(double basic) {
return (basic + 459.67 ) / 1.8;// or whatever is there?
}
});
}
return converters;
}
}
And then :
import java.util.Objects;
public class MeasurePattern {
double value;
String name;
public MeasurePattern(double value, String name) {
this.value = value;
this.name = name;
}
#Override
public String toString() {
return "MeasurePattern{" + "value=" + value + ", name=" + name + '}';
}
#Override
public int hashCode() {
int hash = 7;
hash = 29 * hash + (int) (Double.doubleToLongBits(this.value) ^ (Double.doubleToLongBits(this.value) >>> 32));
hash = 29 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final MeasurePattern other = (MeasurePattern) obj;
if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
public MeasurePattern convertTo(String converter) {
MeasureConverter mycon = MeasureConverter.getConverters().get(name);
MeasureConverter hiscon = MeasureConverter.getConverters().get(converter);
double basic = mycon.valueToBasic(value);
double hisValue = hiscon.basictoValue(basic);
return new MeasurePattern(hisValue, converter);
}
public static void main(String[] args) {
//trying temperatures;
MeasurePattern temp = new MeasurePattern(10, "celsius");
MeasurePattern kelvine = temp.convertTo("kelvine");
MeasurePattern faren = kelvine.convertTo("faren");
MeasurePattern cels = faren.convertTo("celsius");
System.out.println("kelvine = " + kelvine);
System.out.println("faren = " + faren);
System.out.println("cels = " + cels);
}
}
Output:
kelvine = MeasurePattern{value=283.15, name=kelvine}
faren = MeasurePattern{value=412.67777777777775, name=faren}
cels = MeasurePattern{value=9.999999999999943, name=celsius}
You can implement it analog to java.util.concurrent.TimeUnit as an enum. E.g.
public enum DistanceUnit {
KILOMETER {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1;
case MILE:
return 0.621371;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
},
MILE {
#Override
protected double conversionFactor(DistanceUnit toDistanceUnit) {
switch (toDistanceUnit) {
case KILOMETER:
return 1.60934;
case MILE:
return 1;
default:
throw new UnsupportedOperationException(toDistanceUnit + " is not supported");
}
}
};
public double toDistance(double value, DistanceUnit targetDistance) {
return value * conversionFactor(targetDistance);
}
protected abstract double conversionFactor(DistanceUnit toDistanceUnit);
}
change your Distance class to
public class Distance {
double mValue;
DistanceUnit mUnit;
public Distance(double value, DistanceUnit unit){
this.mValue = value;
this.mUnit = unit;
}
public Distance toUnit(DistanceUnit unit){
double newValue = mUnit.toDistance(mValue, unit);
Distance distance = new Distance(newValue, unit);
return distance;
}
#Override
public String toString(){
return String.valueOf(mValue);
}
}
and the client code will look very clear
public class Main {
public static void main(String[] args) {
Distance kilometers = new Distance(265.35, DistanceUnit.KILOMETER);
Distance miles = kilometers.toUnit(DistanceUnit.MILE);
System.out.println(miles);
}
}
will output
164.88079485000003
Java convention does not use a m(ember) prefix (but say a this. qualification), and convention is taken quite seriously in java (as opposed to C++ for instance).
toString misses the unit.
JScience offers more, the capability to calculate in different units, m/s², and so on. Your class is a nice abstraction. But in a wider context, you probably will want to have math operations, powers of units (-2 for s above).
Take a look at your own usage ideas first:
(Just garbage:)
U speedUnit = U.of(Distance::km, Time::h.up(-1));
double timeInS = U.mile(40).div(speedunit(30)).in(U.m);
I think you should use the "Strategy" pattern.
An interface:
public interface DistanceUnit {
double getDistance(int metres);
}
The Inch class:
public class Inch implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters*39; //do conversion here
}
}
The Kilometers class:
public class Kilometres implements DistanceUnit {
#Override
public double getDistance(int metres) {
return meters/1000; //do conversion here
}
}
Then:
List<DistanceUnit> distanceList = new ArrayList<>();
distanceList.add(new Inch());
distanceList.add(new Kilometres());
for (DistanceUnit item : distanceList) {
System.out.println(item.getDistance(1000));
}
If I understand you, I think it is a simple and clean solution.
You can follow this model for conversion between others units.
Is there a way to combine the following 2 Statesments?
Map<Integer,Double> collX = listeAllerPunkte.stream().collect(groupingBy(DataPoint::getId,
averagingDouble(DataPoint::getX)));
Map<Integer,Double> collY = listeAllerPunkte.stream().collect(groupingBy(DataPoint::getId,
averagingDouble(DataPoint::getY)));
I have a Class DataPoints like this:
public class DataPoint {
public final double x;
public final double y;
private int Id;
public DataPoint(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public int getId() {
return Id;
}
}
The Id contains a Random value between 0-5.
listeAllerPunkte is a List with a lot of DataPoints
Now I want to create a DataPoint for each DataPoints in the List with the same Id. The DataPoint should have the average of the x and y values of the Datapoints with the same Id.
With the two Statemantes from the Beginning i must create the DataPoints manually out of the two Maps.
Is there a way to create them directly in the stream?
A general solution would be using a collector which can combine two collectors to process both at once. Unfortunately, such collector does not exist in the standard API, but this answer provide an implementation of such a collector.
Alternatively, you can create a solution for this specific case by creating your own class for holding the summary of points, e.g.
static class DataPointSummary {
long count;
double sumX, sumY;
public double getAverageX() {
return count==0? 0: sumX/count;
}
public double getAverageY() {
return count==0? 0: sumY/count;
}
public void add(DataPoint p) {
count++;
sumX+=p.getX();
sumY+=p.getY();
}
public DataPointSummary merge(DataPointSummary s) {
count+=s.count;
sumX+=s.sumX;
sumY+=s.sumY;
return this;
}
#Override
public String toString() {
return "DataPointSummary["+count+" points"
+", avg x="+getAverageX()+", avg y="+getAverageY()+']';
}
}
Then you may collect your points like
Map<Integer,DataPointSummary> coll = listeAllerPunkte.stream().collect(
groupingBy(DataPoint::getId, Collector.of(
DataPointSummary::new, DataPointSummary::add, DataPointSummary::merge)));
Note that I assumed that you method signature public double getId() is a typo and actually public int getId() as otherwise, the examples in your question won’t work.
The summary implementation above works well if the coordinates of the points have the same magnitude. If you encounter both, very large values and very small values within the same group, you may need a summing with error compensation algorithm. Instead of implementing it yourself, I recommend using the summary implementation of the JRE instead:
static class DataPointSummary {
final DoubleSummaryStatistics x=new DoubleSummaryStatistics();
final DoubleSummaryStatistics y=new DoubleSummaryStatistics();
public double getAverageX() {
return x.getAverage();
}
public double getAverageY() {
return y.getAverage();
}
public void add(DataPoint p) {
x.accept(p.getX());
y.accept(p.getY());
}
public DataPointSummary merge(DataPointSummary s) {
x.combine(s.x);
y.combine(s.y);
return this;
}
#Override
public String toString() {
return "DataPointSummary["+x.getCount()+" points"
+", avg x="+getAverageX()+", avg y="+getAverageY()+']';
}
}
This variant is used the same way as the first one.