Skip to content

Instantly share code, notes, and snippets.

@rponte
Last active January 19, 2023 19:34
Show Gist options
  • Save rponte/70ec0a7c109bb58121f246dd1372154d to your computer and use it in GitHub Desktop.
Save rponte/70ec0a7c109bb58121f246dd1372154d to your computer and use it in GitHub Desktop.
Algoritimos: Encontrar menor lance (valor) único em uma lista
--
-- drop a cria tabela
--
drop table tb_lances;
create table tb_lances (VALOR number not null);
--
-- limpa e popula tabela
--
delete from tb_lances;
insert all
into tb_lances values (10)
into tb_lances values (30)
into tb_lances values (20) -- menor lance unico
into tb_lances values (10)
select * from dual
;
--
-- logica em uma query
--
select min(valor) as menor_lance_unico
from (
select l.*
,count(*) as total
from tb_lances l
group by l.valor
having count(*) = 1
order by l.valor asc -- obs: desnecessario! :-)
)
;
import static java.util.Comparator.naturalOrder;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import java.util.stream.Collectors;
import java.util.stream.Comparator;
import java.util.*;
public class Sorteio {
/**
* Solução simples com a API Collections do Java (nada de Guava, Commons-Collections etc)
*/
public Integer sorteia(List<Integer> lances) {
SortedSet<Integer> unicos = new TreeSet<>(); // mantem ordem natural
Set<Integer> duplicados = new HashSet<>();
for (Integer lance : lances) {
if (!unicos.add(lance)) {
duplicados.add(lance);
}
}
unicos.removeAll(duplicados); // remove TODOS os duplicados
return unicos.first(); // retorna o primeiro
}
/**
* Solução quando não se tem muito conhecimento da API Collections do Java
*/
public int sorteia2(List<Integer> lances) {
// agrupamos por valor
Map<Integer, Integer> lancesPorValor = new HashMap<>();
for (Integer lance : lances) {
if (!lancesPorValor.containsKey(lance)) {
lancesPorValor.put(lance, 0);
}
int total = lancesPorValor.get(lance);
lancesPorValor.put(lance, ++total);
}
// identificamos e selecionamos os lances unicos
List<Integer> unicos = new ArrayList<>();
for (Entry<Integer, Integer> entry : lancesPorValor.entrySet()) {
if (entry.getValue() == 1) {
unicos.add(entry.getKey());
}
}
// ordenamos lances por ordem crescente
Collections.sort(unicos);
// pegamos o 1o item, ou seja, o menor
return unicos.get(0);
// ou usando min()
// return Collections.min(unicos);
}
/**
* Usando API de Streams do Java 8
*/
public Integer sorteiaComJava8(List<Integer> lances) {
Integer lance = lances.stream()
.collect(Collectors.groupingBy(Integer::intValue, Collectors.counting())) // agrupa e conta
.entrySet()
.stream()
.filter(e -> e.getValue() == 1) // elimina os repetidos
.map(e -> e.getKey())
.min(Comparator.comparingInt(Integer::intValue)) // min() ou sorting+first
.orElse(null)
;
return lance;
}
/**
* Usando API de Streams do Java 8 de forma mais clean
*/
public Integer sorteiaComJava8_clean(List<Integer> lances) {
Integer lance = lances.stream()
.collect(groupingBy(identity(), counting())) // agrupa e conta
.entrySet()
.stream()
.filter(e -> e.getValue() == 1) // elimina os repetidos
.map(Map.Entry::getKey)
.min(naturalOrder()) // min() ou sorting+first
.orElse(null)
;
return lance;
}
}
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class SorteioTest {
@Test
public void deveEncontrarOMenorLanceUnico() {
List<Integer> lances = Arrays.asList(1, 2, 2, 3, 4, 1, 5, 6, 7, 8, 6, 7, 3, 9);
Sorteio sorteio = new Sorteio();
Integer valor = sorteio.sorteia(lances);
assertEquals("menor valor unico", 4, valor.intValue());
}
@Test
public void naoDeveEncontrarOMenorLanceUnico_quandoNaoHouverLances() {
// cenario
List<Integer> lances = Arrays.asList();
// ação
Sorteio fordKa = new Sorteio();
Integer menorLanceUnico = fordKa.sorteiaComJava8(lances);
// validação
assertEquals(null, menorLanceUnico);
}
}
@juanplopes
Copy link

Que saudade do LINQ. Ficaria bem melhor que isso:

valores.stream()
        .collect(groupingBy(identity(), counting()))
        .entrySet()
        .stream()
        .filter(x -> x.getValue() == 1)
        .map(Map.Entry::getKey)
        .min(Comparator.naturalOrder())
        .orElse(null);

@juanplopes
Copy link

Como ficaria em C#:

return list
    .GroupBy (x => x)
    .Where(x => x.Count() == 1)
    .Min(x => x.Key);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment