Banner escrito: Ordenação Alfabética de Forma Poliglota - Colocar lista de palavras em ordem é tarefa simples e também um bom exemplo para comparar linguagens de programação como C#, Python e JS seja para poliglota iniciante ou experiente 🌎

- 9 min de leitura

Tags: tutorial

Ordenação Alfabética de Forma Poliglota

Olá e boas vindas!

Mesmo parecendo uma tarefa simples, ordenar alfabeticamente um array em linguagens de programação traz uma oportunidade de vislumbrar suas semelhanças e como elas funcionam internamente, algo interessante para aprendizes e experientes!

Listei aqui o código e um pouco sobre a implementação das linguagens C#Abrir em nova aba, JSAbrir em nova aba e PythonAbrir em nova aba (lista podendo aumentar futuramente).

Em cada linguagem usei 100 mil palavras embaralhadas e uma função de benchmarkAbrir em nova aba para comparar os métodos usados (resultados dependem do ambiente)!

Quando usar?

Indicado

Uma ordenação direto no código tem seus casos de uso, ex: dicionários e uma listagem de usuários/tarefas em ambiente sem banco de dados, como consumindo um JSON.

💡 Usei nos simples dicionários daqui, veja a escrita de um aquiAbrir em nova aba

Contraindicado

Vale deixar registrado que enquanto pode ser algo rápido e funcional, raramente uma ordenação via código será recomendada em aplicações do mundo real.

Nessas temos um grande fluxo de dados e um banco de dados bem estruturado sendo perfeito para armazená-los ao lado de funções de ordenação performáticas!

C Sharp

O algoritmo interno de ordenação do C# é o IntroSortAbrir em nova aba, ou seja, por debaixo dos panos este será aplicado no array ao usar o padrão Array.Sort()Abrir em nova aba.

E como esta ordenação se baseia no UnicodeAbrir em nova aba da string, dando valores distantes para a mesma letra maiúscula ou com acentos, para funcionar alfabeticamente é necessário usar o StringComparerAbrir em nova aba configurado com nosso idioma específico:

using System;
using System.Diagnostics; // benchmark
using System.Globalization; // CultureInfo
using System.Linq; // Enumerable/OrderBy

class Program
{
  static void Main()
  {
    string[] palavras = {
      "árvore", "éter", "coração", "zebra", "banana", "ônibus", "elefante", "fácil", "cálculo", "máquina"
    };

    // Essas 10 palavras x 10k pra virar 100k e usar em benchmark
    palavras = Enumerable.Repeat(palavras, 10000).SelectMany(x => x).ToArray();
    Random rand = new Random();
    // Embaralhando
    palavras = palavras.OrderBy(x => rand.Next()).ToArray();

    // Deixando array original intacto
    var palavrasClone = (string[])palavras.Clone();
    // Inicia benchmark
    var sw = Stopwatch.StartNew();
    // Teste 1: Ordenação padrão
    Array.Sort(palavrasClone);
    sw.Stop();
    // Exibe o tempo que passou em milissegundos
    Console.WriteLine($"Ordenação padrão: {sw.ElapsedMilliseconds} ms");

    palavrasClone = (string[])palavras.Clone();
    sw.Restart();
    // Teste 2: Usando comparador de String configurado pra pt-BR
    Array.Sort(palavrasClone, StringComparer.Create(new CultureInfo("pt-BR"), true));
    sw.Stop();
    Console.WriteLine($"Ordenação localizada: {sw.ElapsedMilliseconds} ms");
  }
}

Resultado no terminal:

> Ordenação localizada: 162 ms
> Ordenação padrão: 162 ms

💡 No CultureInfo()Abrir em nova aba poderia ser usado facilmente outro código de idioma, como en-US, eis outro lado do poliglota no título :)

JavaScript

O algoritmo interno do JS é o mais curioso, pois enquanto o V8Abrir em nova aba usado no Node.jsAbrir em nova aba usa o TimSortAbrir em nova aba este JavaScript executado nos navegadores depende totalmente de qual implementação da especificaçãoAbrir em nova aba foi escrita neles, pois a linguagem a usará!

No Chrome e Safari é usado o TimSort, mas o Firefox usa o QuickSortAbrir em nova aba, o que gera uma diferença na performance do mesmo código!

Para ir além da padrão que usa Unicode ao invés do alfabeto, usamos o String.localeCompare()Abrir em nova aba, como a seguir:

const palavras = [
  "árvore", "Éter", "coração", "zebra", "banana", "ônibus", "elefante", "fácil", "cálculo", "máquina"
];

// Essas 10 palavras x 10k pra virar 100k e usar em benchmark
const muitasPalavras = palavras
  .map(palavra => Array(10000).fill(palavra))
  .flat()
  .sort(() => Math.random() - 0.5); // Embaralhando

// Função para medir o tempo de execução
function medirTempo(funcao, descricao) {
  const start = performance.now();
  funcao();
  const end = performance.now();
  console.log(`${descricao}: ${end - start}ms`);
}

// Teste 1
medirTempo(() => {
  muitasPalavras.sort();
}, 'Ordenação padrão');

// Teste 2
medirTempo(() => {
  muitasPalavras.sort((a, b) => a.localeCompare(b, 'pt-BR'));
}, 'Ordenação localizada');

Resultado no Terminal:

Ordenação padrão: 20ms
Ordenação localizada: 32ms

Python

O Tim PetersAbrir em nova aba, criador do TimSort (e de nada mais nada menos que o Zen of PythonAbrir em nova aba), contribuiu muito com o Python desde sua implementação original, então é natural este ser o algoritmo padrão no sorted()Abrir em nova aba.

Porém, como nas outras linguagens, a ordenação padrão usa a tabela Unicode ao invés do alfabeto, nos obrigando a ir mais além configurando um locale.setlocale()Abrir em nova aba:

import time # para benchmark
import locale # para definir local
import random # para misturar dados

# Geração de lista grande de palavras com acentos
palavras = ["árvore", "Éter", "coração", "zebra", "banana", "ônibus", "elefante", "fácil", "cálculo", "máquina"]
# Multiplicando para aumentar o tamanho da lista
palavras *= 10000
# Misturando para não ter ordenação prévia
random.shuffle(palavras)

# Teste 1
start = time.time()
sorted_padrao = sorted(palavras)
print(f"Ordenação padrão: {time.time() - start:.4f} segundos")

# Teste 2 (culturalmente correto)
locale.setlocale(locale.LC_ALL, "pt_BR.UTF-8")
start = time.time()
# argumento `key=` altera a função de ordenação padrão
sorted_locale = sorted(palavras, key=locale.strxfrm)
print(f"Ordenação localizada: {time.time() - start:.4f} segundos")

Resultado no Terminal:

Ordenação padrão: 0.0629 segundos
Ordenação localizada: 0.0909 segundos

⚠️ Um porém a se atentar é que o Python só pode ser configurado usando os locales disponíveis na máquina, ex: código executado em servidor europeu pode não ter o "pt_BR" e finalizar com erro.

Conclusão

Quis registrar aqui pro futuro Eu as formas com que já realizei uma mesma coisa de rotina em diversas linguagens e acabei anotando um pouco de suas histórias, decisões de implementação, algoritmos usados internamente, performance e como tudo mesmo assim culminou em um código bem semelhante!

E são essas visões da TI que quero seguir compartilhando 🥳🎉

Agradeço a atenção e até 🚀

Fontes e Futuras Ideias