# Positions Average in Java

## The challenge

Suppose you have 4 numbers: `'0', '9', '6', '4'` and 3 strings composed with them:

```s1 = "6900690040"
s2 = "4690606946"
s3 = "9990494604"
```

Compare `s1` and `s2` to see how many positions they have in common: `0` at index 3, `6` at index 4, `4` at index 8 ie 3 common positions out of ten.

Compare `s1` and `s3` to see how many positions they have in common: `9` at index 1, `0` at index 3, `9` at index 5 ie 3 common positions out of ten.

Compare `s2` and `s3`. We find 2 common positions out of ten.

So for the 3 strings we have 8 common positions out of 30 ie 0.2666… or 26.666…%

Given `n` substrings (n >= 2) in a string `s` our function `pos_average` will calculate the average percentage of positions that are the same between the `(n * (n-1)) / 2` sets of substrings taken amongst the given `n` substrings. It can happen that some substrings are duplicate but since their ranks are not the same in `s` they are considered as different substrings.

The function returns the percentage formatted as a float with 10 decimals but the result is tested at 1e.-9 (see function assertFuzzy in the tests).

### Example:

Given string s = “444996, 699990, 666690, 096904, 600644, 640646, 606469, 409694, 666094, 606490” composing a set of n = 10 substrings (hence 45 combinations), `pos_average` returns `29.2592592593`.

In a set the `n` substrings will have the same length ( > 0 ).

## The solution in Java code

Option 1:

```public class PositionAverage {

public static double posAverage(String s) {
String[] strings = s.split(",");
int matchs = 0;
double of = 0;
for (int i = 0; i < strings.length; i++)
strings[i] = strings[i].trim();
for (int i = 0; i < strings.length; i++) {
for (int j = i + 1; j < strings.length; j++)
for (int k = 0; k < strings[i].length(); k++) {
matchs += (strings[i].charAt(k) == strings[j].charAt(k)) ? 1 : 0;
of++;
}
}
return matchs * 100 / of;
}
}
```

Option 2:

```class PositionAverage {
private static double pairPercentage(String s1, String s2) {
int lg = s1.length(); int count = 0;
for (int pos = 0; pos < lg; pos++) {
if (s1.charAt(pos) == s2.charAt(pos))
count += 1;
}
return (double)count / lg;
}
public static double posAverage(String s) {
String[] strings = s.split(", ");
double result = 0.0; int cnt = 0; int lg = strings.length;
for (int k = 0; k < lg; k++) {
for (int i = k + 1; i < lg; i++) {
result += pairPercentage(strings[k], strings[i]);
cnt += 1;
}
}
result = 100.0 * result / cnt;
return Math.floor(result * Math.pow(10.0, 10)) / Math.pow(10.0, 10);
}
}
```

Option 3:

```public class PositionAverage {

public static double posAverage(String s) {
long posCount = 0;
long matchCount = 0;

String[] parts = s.split(", ");

for(int i=0; i<parts.length-1; i++){
for(int k=i+1; k<parts.length; k++){
for(int z=0; z<parts[k].length(); z++){
posCount++;
if(parts[i].charAt(z)==parts[k].charAt(z)) matchCount++;
}
}
}

return (double)matchCount / (double) posCount * 100.0;
}
}
```

## Test cases to validate our solution

```import org.junit.Test;
import org.junit.runners.JUnit4;
import static org.junit.Assert.*;
import org.junit.Test;

public class PositionAverageTest {

private static void assertFuzzy(String s, double exp){
System.out.println("Testing " + s);
boolean inrange;
double merr = 1e-9;
double actual = PositionAverage.posAverage(s);
inrange = Math.abs(actual - exp) <= merr;
if (inrange == false) {
System.out.println("Expected mean must be near " + exp +", got " + actual);
}
assertEquals(true, inrange);
}
@Test
public void test() {
assertFuzzy("466960, 069060, 494940, 060069, 060090, 640009, 496464, 606900, 004000, 944096", 26.6666666667);
assertFuzzy("444996, 699990, 666690, 096904, 600644, 640646, 606469, 409694, 666094, 606490", 29.2592592593);
assertFuzzy("4444444, 4444444, 4444444, 4444444, 4444444, 4444444, 4444444, 4444444", 100);
assertFuzzy("0, 0, 0, 0, 0, 0, 0, 0", 100);
}
}

```
Tags:
Subscribe
Notify of