Richest Customer Wealth

Richest Customer Wealth


Mais um exercício inicial do LeetCode feito com sucesso e mais uma simplificação de função alcançada. Veja como os conceitos mais básicos da linguagem podem ser abstraídos para funções padrões que lhe permitirão uma maior verbosidade.

Regra de Negócio

Receberemos uma lista contendo outras listas, exemplo [ [12, 23], [19, 3], ... ], onde cada lista contendo números representa um usuário/cliente, e cada número representa uma conta bancária diferente.

A proposta do exercício é retornar o saldo do usuário mais rico, somando o valor de suas contas individuais para determinar sua fortuna, que por sua vez será comparada ao montante dos outros usuários.

Exemplo

  • Input: [[1,2,3], [1,2,7]]
  • Output: 10

Como a soma do cliente 1 [1 + 2 + 3] obteve o valor 6, enquanto a soma do cliente 2 [1 + 2 + 7] obteve o valor 10, o resultado retornado pela função deverá ser 10 por ser o maior saldo entre os clientes.

Solução

Para solucionar esse problema pensei na maneira mais prática e intuitiva, que consiste em:

  1. Criar uma variável max, para armazenar o maior valor existente;
  2. Iterar sobre a primeira lista, podendo manipular cliente a cliente;
  3. Criar uma variável sum, para armazenar a soma das contas de um cliente;
  4. Iterar sobre as contas do cliente, armazenando o valor somando na variável sum criada fora do loop;
  5. Fora do loop, verificar se o valor da variável sum é maior que o valor da variável max;
    1. Caso seja maior —> O valor de sum passa para max;
    2. Caso seja menor —> O valor de sum volta a ser 0;

Primeira Solução

pub fn maximum_wealth(accounts: Vec<Vec<i32>>) -> i32 {
    let mut max: i32 = 0;
    for account in accounts.iter() {
        let mut sum = 0;
        for num in account.iter() {
            sum += num;
        }
        if sum > max {
            max = sum;
        }
    }
    max
}

Por mais que essa primeira solução não seja difícil de compreender, fiquei encanado em melhorar sua escrita, de forma a simplificar sua abordagem e reduzir o número de linhas utilizado para resolver o problema.

Solução Final

Foi então que, após muita pesquisa a respeito dos métodos e consumidores de um iterador resolvi utilizar a combinação dos métodos map, sum e do consumidor max.

  • Map: O método map pode ser muito semelhante a um For loop, com a diferença de ser lazy, que é muito recomendado se já estiver trabalhando com outro iterador;
  • Sum: O método sum soma todos os items de um iterador;
  • Max: o consumidor max percorre um iterador retornando o maior valor encontrado;
pub fn maximum_wealth(accounts: Vec<Vec<i32>>) -> i32 {
    accounts.iter()
        .map(|account| account.iter().sum())
        .max()
        .unwrap()
}

Conclusão

Levando todos aqueles pontos em consideração foi possível montar nossa solução final, que em apenas quatro linhas consegue resolver o problema proposto de maneira elegante, tornando mais fácil seu entendimento e manutenção.

Não são todos os casos em que uma simplificação como esta poderá trazer vantagens a seu código, mas acredito que dentro de um contexto de aprendizado, brincar com as funções padrão da linguagem pode ser uma boa maneira de evitar dores de cabeça no futuro, quando você se deparar com problemas reais que implicam em manipulações complexas de estruturas ainda mais complexas.

O Benchmark realizado em ambas as funções pode ser encontrado no Rust Playground - Richest Customer Wealth, no entanto a diferença entre suas velocidades não é nem um pouco expressiva, além de variável muito baseado na quantidade de loops consecutivos que serão realizados.

← Artigos