Localizando o valor max / min em uma matriz de primitivas usando Java

185

É trivial escrever uma função para determinar o valor mínimo / máximo em uma matriz, como:

/**
 * 
 * @param chars
 * @return the max value in the array of chars
 */
private static int maxValue(char[] chars) {
    int max = chars[0];
    for (int ktr = 0; ktr < chars.length; ktr++) {
        if (chars[ktr] > max) {
            max = chars[ktr];
        }
    }
    return max;
}

mas isso já não foi feito em algum lugar?

Nick Heiner
fonte
8
A matriz primitiva para a matriz de contêineres ajudaria: stackoverflow.com/questions/3770289/… seguida por Collections.max(Arrays.asList()).
Ciro Santilli # 13/15
Eu simplesmente amo como o Java é burro
Farid

Respostas:

173

Usando o Commons Lang (para converter) + Coleções (para min / max)

import java.util.Arrays;
import java.util.Collections;

import org.apache.commons.lang.ArrayUtils;

public class MinMaxValue {

    public static void main(String[] args) {
        char[] a = {'3', '5', '1', '4', '2'};

        List b = Arrays.asList(ArrayUtils.toObject(a));

        System.out.println(Collections.min(b));
        System.out.println(Collections.max(b));
   }
}

Observe que Arrays.asList()agrupa a matriz subjacente; portanto, ela não deve consumir muita memória e não deve executar uma cópia nos elementos da matriz.

Michael Rutherfurd
fonte
9
o que éArrayUtils
Basheer AL-MOMANI
4
Arrays.asList()deve ficar bem, mas ArrayUtils.toObject()copiará cada elemento de apara uma nova matriz de Character.
EM
5
Arrays.asList(a)não funciona Você não pode fazer uma lista de primitivas ( List<char>neste caso). Primeiro você precisa converter os valores primitivos em objetos e é por isso que ArrayUtils.toObjecté usado.
nessa.gp
96

Você pode simplesmente usar as novas Java 8 Streams mas você tem que trabalhar com int.

O streammétodo da classe de utilitário Arraysfornece um método IntStreamno qual você pode usar o minmétodo. Você também pode fazer max, sum, average, ...

O getAsIntmétodo é usado para obter o valor doOptionalInt

import java.util.Arrays;

public class Test {
    public static void main(String[] args){
        int[] tab = {12, 1, 21, 8};
        int min = Arrays.stream(tab).min().getAsInt();
        int max = Arrays.stream(tab).max().getAsInt();
        System.out.println("Min = " + min);
        System.out.println("Max = " + max)
    }

}

== ATUALIZAÇÃO ==

Se o tempo de execução for importante e você desejar analisar os dados apenas uma vez, poderá usar o summaryStatistics()método como este

import java.util.Arrays;
import java.util.IntSummaryStatistics;

public class SOTest {
    public static void main(String[] args){
        int[] tab = {12, 1, 21, 8};
        IntSummaryStatistics stat = Arrays.stream(tab).summaryStatistics();
        int min = stat.getMin();
        int max = stat.getMax();
        System.out.println("Min = " + min);
        System.out.println("Max = " + max);
    }
}

Essa abordagem pode oferecer um desempenho melhor que o loop clássico, porque o summaryStatisticsmétodo é uma operação de redução e permite paralelização.

Ortomala Lokni
fonte
57

A biblioteca do Google Guava possui métodos min e max em suas classes Chars, Ints, Longs etc.

Então você pode simplesmente usar:

Chars.min(myarray)

Nenhuma conversão é necessária e, presumivelmente, é implementada com eficiência.

Andrew McKinlay
fonte
4
É implementado mais ou menos como na pergunta, exceto que lança uma IllegalArgumentException para uma matriz de comprimento 0. ( code.google.com/p/guava-libraries/source/browse/trunk/src/com/… )
ColinD
3
Esta é a melhor solução de tudo aqui. Evita toda essa confusão de java.util.Arrays # asList varargs.
21480 Kong
20

Sim, é feito na classe Coleções . Observe que você precisará converter sua matriz de caracteres primitiva em um caractere [] manualmente.

Uma breve demonstração:

import java.util.*;

public class Main {

    public static Character[] convert(char[] chars) {
        Character[] copy = new Character[chars.length];
        for(int i = 0; i < copy.length; i++) {
            copy[i] = Character.valueOf(chars[i]);
        }
        return copy;
    }

    public static void main(String[] args) {
        char[] a = {'3', '5', '1', '4', '2'};
        Character[] b = convert(a);
        System.out.println(Collections.max(Arrays.asList(b)));
    }
}
Bart Kiers
fonte
1
Collections.min (myCollection); Se você quiser usá-lo para matrizes, poderá fazê-lo como Collections.min (Arrays.asList (myArray));
Zed
3
converter a char []para Character []apenas para determinar o máximo é bastante ineficiente - crie melhor uma classe de utilitário com métodos estáticos para cada tipo primitivo semelhante a java.util.Arrays: java.sun.com/javase/6/docs/api/java/util/Arrays.html
Christoph
@Christoph: sim, se o tamanho da matriz for grande, eu concordo. Simplesmente declarar que é "ineficiente" não faz sentido se o aplicativo em questão fizer muitas chamadas ao banco de dados e / ou operações de E / S e o tamanho da matriz for (relativamente) pequeno.
Bart Kiers
você deve usar em Character.valueOf(chars[i])vez de new Character(chars[i])por motivos de desempenho: java.sun.com/javase/6/docs/api/java/lang/…
Christoph
@Christoph Christoph está certo, é ineficiente e estúpido transformar uma matriz em uma coleção, para uma pesquisa mínima máxima.
AlexWien #
16
import java.util.Arrays;

public class apples {

  public static void main(String[] args) {
    int a[] = {2,5,3,7,8};
    Arrays.sort(a);

     int min =a[0];
    System.out.println(min);
    int max= a[a.length-1];
    System.out.println(max);

  }

}
Lubna_Nsour
fonte
4
Por favor, forneça alguma explicação.
18714 Mike
3
Eu acho que o que isso significa dizer é que, se você classificar o array (em ordem crescente), por definição, o valor mínimo sempre estará na primeira posição, um [0], e o valor máximo sempre estará na última posição , [a.length-1].
Jeff
1
Essa é uma maneira legítima e útil de resolver o problema. Qual é a desvantagem de usá-lo em comparação com os outros?
Alex
8
@ complexidade do tempo alex - a classificação é, na melhor das hipóteses, uma questão O (nlogn), enquanto a abordagem de Michael Rutherfurd é O (n).
precisa saber é
3
Não precisamos classificar, pois a iteração única na lista é suficiente para encontrar mín e máx.
akhil_mittal 23/02
11

Eu tenho uma pequena classe auxiliar em todos os meus aplicativos com métodos como:

public static double arrayMax(double[] arr) {
    double max = Double.NEGATIVE_INFINITY;

    for(double cur: arr)
        max = Math.max(max, cur);

    return max;
}
Sauer
fonte
1
Você deve usar o dobro max = Double.NEGATIVE_INFINITY; em vez de duplo max = Double.MIN_VALUE; Como MIN_VALUE para o dobro é positivo
Krems
1
... ou você pode definir max para o primeiro item da matriz e iterar a partir do segundo item, veja minha resposta.
Nicholas Hamilton
3

Você poderia facilmente fazê-lo com um IntStreameo max()método.

Exemplo

public static int maxValue(final int[] intArray) {
  return IntStream.range(0, intArray.length).map(i -> intArray[i]).max().getAsInt();
}

Explicação

  1. range(0, intArray.length)- Para obter um fluxo com tantos elementos quanto presentes no intArray.

  2. map(i -> intArray[i])- Mapeie todos os elementos do fluxo para um elemento real do intArray.

  3. max()- Obtenha o elemento máximo desse fluxo como OptionalInt.

  4. getAsInt()- Desembrulhe o OptionalInt. (Você também pode usar aqui: orElse(0)caso OptionalIntesteja vazio.)

winklerrr
fonte
2

Aqui está uma classe de utilitário que fornece min/maxmétodos para tipos primitivos: Primitives.java

Christoph
fonte
2
import java.util.Random;

public class Main {

public static void main(String[] args) {
   int a[] = new int [100];
   Random rnd = new Random ();

    for (int i = 0; i< a.length; i++) {
        a[i] = rnd.nextInt(99-0)+0;
        System.out.println(a[i]);
    }

    int max = 0;          

    for (int i = 0; i < a.length; i++) {
        a[i] = max;


        for (int j = i+1; j<a.length; j++) {
            if (a[j] > max) {
               max = a[j];
            }

        }
    }

    System.out.println("Max element: " + max);
}
}
mark2
fonte
2
    public int getMin(int[] values){
        int ret = values[0];
        for(int i = 1; i < values.length; i++)
            ret = Math.min(ret,values[i]);
        return ret;
    }
Nicholas Hamilton
fonte
Esta é para os números int, mas a questão está pedindo valores primitivosint, long, char, byte....
IgniteCoders
2

Uma solução com reduce():

int[] array = {23, 3, 56, 97, 42};
// directly print out
Arrays.stream(array).reduce((x, y) -> x > y ? x : y).ifPresent(System.out::println);

// get the result as an int
int res = Arrays.stream(array).reduce((x, y) -> x > y ? x : y).getAsInt();
System.out.println(res);
>>
97
97

No código acima, reduce()retorna dados no Optionalformato, que você pode converter em intpelo getAsInt().

Se quisermos comparar o valor máximo com um determinado número, podemos definir um valor inicial em reduce():

int[] array = {23, 3, 56, 97, 42};
// e.g., compare with 100
int max = Arrays.stream(array).reduce(100, (x, y) -> x > y ? x : y);
System.out.println(max);
>>
100

No código acima, quando reduce()com uma identidade (valor inicial) como o primeiro parâmetro, ele retorna dados no mesmo formato que a identidade. Com essa propriedade, podemos aplicar esta solução a outras matrizes:

double[] array = {23.1, 3, 56.6, 97, 42};
double max = Arrays.stream(array).reduce(array[0], (x, y) -> x > y ? x : y);
System.out.println(max);
>>
97.0
Simon Z.
fonte
1

Exemplo com float:

public static float getMaxFloat(float[] data) {

    float[] copy = Arrays.copyOf(data, data.length);
    Arrays.sort(copy);
    return copy[data.length - 1];
}

public static float getMinFloat(float[] data) {

    float[] copy = Arrays.copyOf(data, data.length);
    Arrays.sort(copy);
    return copy[0];
}
Andrey
fonte
Enquanto sua solução funcionará, mas aumentará a complexidade do tempo para O (nlogn) enquanto min pode ser encontrado facilmente em O (n) usando outras respostas.
Pramod
simplesmente louco para usar uma espécie nesta situação.
Nicholas Hamilton
Pode ser útil quando o primeiro n> 1 menor / maior valor for necessário, com alguns reparos.
biziclop
1

Aqui está uma solução para obter o valor máximo em cerca de 99% das execuções (altere 0,01 para obter um resultado melhor):

public static double getMax(double[] vals){
    final double[] max = {Double.NEGATIVE_INFINITY};

    IntStream.of(new Random().ints((int) Math.ceil(Math.log(0.01) / Math.log(1.0 - (1.0/vals.length))),0,vals.length).toArray())
            .forEach(r -> max[0] = (max[0] < vals[r])? vals[r]: max[0]);

    return max[0];
}

(Não é completamente sério)

mnzl
fonte
;-) Isso é "Não é completamente sério", tudo bem. Hesitando em votar…
Ole VV
0

Passe a matriz para um método que a classifique, Arrays.sort()para classificar apenas a matriz que o método está usando e, em seguida, define min para array[0]e max para array[array.length-1].

whoduexpect
fonte
3
Provavelmente é importante notar que a) Isso modifica a matriz, e b) para matrizes de grandes dimensões é uma solução mais cara O (n nlog) em vez de O (n)
davidsheldon
0

A maneira básica de obter o valor mínimo / máximo de uma matriz. Se você precisar da matriz não classificada, poderá criar uma cópia ou passá-la para um método que retorne o mínimo ou o máximo. Caso contrário, a matriz classificada é melhor, pois ela executa mais rapidamente em alguns casos.

public class MinMaxValueOfArray {
    public static void main(String[] args) {
        int[] A = {2, 4, 3, 5, 5};
        Arrays.sort(A);
        int min = A[0];
        int max = A[A.length -1];
        System.out.println("Min Value = " + min);        
        System.out.println("Max Value = " + max);
    }
}
Kim G.
fonte
2
O problema com a classificação é que ele possui uma sobrecarga de O (n log n) para um problema de O (n). Mas isso é melhor do que as outras três respostas "classificar a matriz" já fornecidas.
Teepeemm