Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Min value of adjacent array

Tags:

java

arrays

I need help with this problem, I need an array 3x5 and then when the user selects a position the output will show the min value of the adjacents numbers. Like this:

3 5 6 7 8
6 7 8 2 3
0 9 2 1 1

And the user selects the position 1,1. // Diagonals count it too.

Output: The min value around is 0.

This is the code that I have, the problem is I´m asking if there is a better way than spamming if and elses everywhere.

private static int checkAdjacentField(int p1, int p2, int[][] ae) {
    int min = Integer.MAX_VALUE;

    if (p1 == 0) {
        if (p2 == 0) {
            if (ae[p1][p2+1] < min) {
                min = ae[p1][p2+1];
            } else if (ae[p1+1][p2+1] < min) {
                min = ae[p1+1][p2+1];
            } else if (ae[p1+1][p2] < min) {
                min = ae[p1+1][p2];
            }
        } else if (p2 == 1) {
            if (ae[p1][p2+1] < min){
                min = ae[p1][p2+1];
            } else if (ae[p1+1][p2+1] < min) {
                min = ae[p1+1][p2+1];
            } else if (ae[p1+1][p2] < min) {
                min = ae[p1+1][p2];
            } else if (ae[p1+1][p2-1] < min) {
                min = ae[p1+1][p2-1];
            } else if (ae[p1][p2-1] < min) {
                min = ae[p1][p2-1];
            }
        }
    }

    return min;
}

public static void main(String[] args) throws IOException {

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    Random r = new Random();

    int [][] ar = new int[3][5];

    for (int i = 0; i < ar.length; i++) {
        System.out.println();
        for (int j = 0; j < 5; j++) {
            int rand = r.nextInt(9) + 1;
            ar[i][j]=rand;
            System.out.printf("%3d",ar[i][j]);
        }
    }
    System.out.println();

    System.out.println("Select a position [][]: ");
    int pos1 = Integer.parseInt(br.readLine());
    int pos2 = Integer.parseInt(br.readLine());

    System.out.println("The min value around is " + checkAdjacentField(pos1,pos2,ar));
}
}

In the code the 0,0 and 0,1 works and yes, I could spend time doing the spamming method of if else but I want to know if there is a better way so I can improve. Thanks for helping, any idea or answer is welcome.

like image 893
BlackoutDev Avatar asked Dec 23 '22 20:12

BlackoutDev


2 Answers

I think the best way to do that is using the following algo:

  • List of all the adjacent positions (regardless of if they are in the array or not)
  • Filter out the ones that are not in the array
  • Map the remaining positions to their values in the array
  • Lookup the smallest one (as we are dealing with integers, you can sort them and take the first one)

this way :

private static int checkAdjacentField(int col, int row, int[][] ae) {
    int nbRows = ae.length;
    int nbCols = ae[0].length;

    // Stream all the 8 positions around your position
    Stream<Point> positions = Stream.of(       
            new Point(col-1, row-1), new Point(col-1, row), new Point(col-1, row+1),
            new Point(col, row-1), new Point(col, row+1),
            new Point(col+1, row-1), new Point(col+1, row), new Point(col+1, row+1));

    return positions
            .filter(p -> p.x>=0 && p.y>=0 && p.x<nbCols && p.y<nbRows)   // keep those inbound
            .mapToInt(p -> ae[p.y][p.x])      // replace positions by their values in the array
            .sorted()                         // sort the values
            .findFirst().orElse(-1);          // take the first one (smallest) 
}

You could even generate the list of points, instead of hard coding them

private static int checkAdjacentField(int col, int row, int[][] ae) {
    int nbRows = ae.length;
    int nbCols = ae[0].length;

    // Stream all the 8 positions around your position
    Stream<Point> positions = IntStream.rangeClosed(-1, 1).boxed() // -1, 0, 1
            .map(c -> IntStream.rangeClosed(-1, 1).boxed()         // -1, 0, 1
                    .map(r -> new Point(col+c, row+r)))
            .flatMap(p -> p)                                       // to a list
            .filter(p -> !(p.x == col && p.y==row));               // remove center point

    // then same as first example
    return  positions
            .filter(p -> p.x>=0 && p.y>=0 && p.x<nbCols && p.y<nbRows)
            .mapToInt(p -> ae[p.y][p.x])
            .sorted()
            .findFirst().orElse(-1);
}

I prefer hard coding them like in the first example though, it is clearer.

like image 143
Bentaye Avatar answered Jan 07 '23 22:01

Bentaye


How about this?

private static int checkAdjacentField(int p1, int p2, int[][] ae) {
  int[] tmp = new int[8];
  int left = (p2-1) % ae[0].length;
  int right = (p2+1) % ae[0].length;
  int up = (p1-1) % ae.length;
  int down = (p1+1) % ae.length; 

  tmp[0] = ae[up][left];
  tmp[1] = ae[up][p2];
  tmp[2] = ae[up][right];

  tmp[3] = ae[p1][left];
  tmp[4] = ae[p1][right];

  tmp[5] = ae[down][left];
  tmp[6] = ae[down][p2];
  tmp[7] = ae[down][right];

  List<Integer> tmpList = Arrays.stream(tmp).boxed().collect(Collectors.toList());
  return tmpList.stream().mapToInt(i -> i).min().orElse(0);
}

Granted, this doesn't account for edges. If you care about edges, you can use Math.min or Math.max to cover these cases:

private static int checkAdjacentField(int p1, int p2, int[][] ae) {
  int[] tmp = new int[8];
  int left = (Math.max((p2-1),0)) % ae[0].length;
  int right = (Math.min((p2+1), ae[0].length-1)) % ae[0].length;
  int up = (Math.max((p1-1),0)) % ae.length;
  int down = (Math.min((p1+1), ae.length-1)) % ae.length; 

  tmp[0] = ae[up][left];
  tmp[1] = ae[up][p2];
  tmp[2] = ae[up][right];

  tmp[3] = ae[p1][left];
  tmp[4] = ae[p1][right];

  tmp[5] = ae[down][left];
  tmp[6] = ae[down][p2];
  tmp[7] = ae[down][right];

  List<Integer> tmpList = Arrays.stream(tmp).boxed().collect(Collectors.toList());
  return tmpList.stream().mapToInt(i -> i).min().orElse(0);
}
like image 22
Dennis B. Avatar answered Jan 07 '23 22:01

Dennis B.