Para manter valores Swift sintéticos únicos sem alterar a ordem de inserção, percorra o array de entrada uma vez, registre as chaves aceitas em um conjunto e acrescente a um array de saída apenas as primeiras ocorrências. Este guia cria um pequeno cálculo local que você pode executar em um Mac.

A tarefa é processar uma lista ordenada de valores sintéticos de formas, remover os valores repetidos e calcular um total com base nas entradas mantidas. Tudo acontece na memória; o exemplo não lê entradas externas nem salva resultados do cálculo.

Defina o que significa “único” antes de escolher uma coleção

Os arrays Swift preservam a ordem e permitem duplicatas. Os conjuntos contêm valores únicos, mas não têm uma ordem definida. Portanto, converter um array em um conjunto e depois novamente em um array não preserva a ordem da primeira ocorrência. A ordenação posterior estabelece uma ordem de classificação, que pode ser diferente da ordem de inserção. Esses comportamentos das coleções estão documentados em Collection Types do Swift.

Neste exemplo, cada valor sintético tem o nome de uma forma e um tamanho. Por padrão, duas entradas são consideradas duplicatas somente quando ambas as propriedades coincidem. Portanto, um círculo de tamanho 12 e um círculo de tamanho 20 permanecem como valores separados.

Pergunta sobre o contrato Regra deste cálculo
O que determina a ordem de entrada? A posição no array fornecido
O que torna dois valores duplicatas? Forma igual e tamanho igual
Qual ocorrência é mantida? A primeira ocorrência
Uma duplicata posterior desloca o valor mantido? Não
O que acontece com uma entrada vazia? Retorna um array vazio e um total de zero
Quais valores contribuem para o total? Somente os valores mantidos

Este contrato evita um erro comum: remover entradas pelo nome da forma quando o cálculo precisa distinguir combinações de forma e tamanho. O exemplo também calcula o resultado considerando apenas a forma, para que você veja o efeito de alterar essa regra.

Crie um exemplo completo de Swift local no seu Mac

Você precisa ter um toolchain do Swift instalado. No Terminal, execute swift --version para confirmar que o comando está disponível. O tutorial oficial do Swift Build a Command-line Tool documenta essa verificação, a criação de um pacote executável e sua execução.

Crie um novo diretório para o exemplo e inicialize um pacote executável:

mkdir OrderDemo
cd OrderDemo
swift package init --name OrderDemo --type executable

Substitua o arquivo de origem executável gerado em Sources pelo programa completo abaixo. O nome do arquivo gerado e a estrutura de diretórios podem variar conforme o toolchain; substitua o ponto de entrada existente em vez de adicionar um segundo. Este programa usa um ponto de entrada @main, então coloque-o em um arquivo chamado OrderDemo.swift, renomeando um main.swift gerado, se necessário. O tutorial de linha de comando do Swift explica a escolha entre um arquivo main.swift e um ponto de entrada @main.

Não são necessários imports nem dependências de pacote. O programa usa tipos e funções da biblioteca padrão.

struct Tile: Hashable {
    let shape: String
    let size: Int
}

func uniqueFirst<Value, Key: Hashable>(
    _ values: [Value],
    by key: (Value) -> Key
) -> [Value] {
    var seen: Set<Key> = []
    var result: [Value] = []

    for value in values {
        if seen.insert(key(value)).inserted {
            result.append(value)
        }
    }

    return result
}

@main
struct OrderDemo {
    static func main() {
        let input = [
            Tile(shape: "circle", size: 12),
            Tile(shape: "square", size: 8),
            Tile(shape: "circle", size: 12),
            Tile(shape: "circle", size: 20),
            Tile(shape: "square", size: 8)
        ]

        let retained = uniqueFirst(input, by: { $0 })
        let total = retained.reduce(0) { $0 + $1.size }
        let skipped = input.count - retained.count

        let expected = [
            Tile(shape: "circle", size: 12),
            Tile(shape: "square", size: 8),
            Tile(shape: "circle", size: 20)
        ]
        precondition(retained == expected)
        precondition(total == 40)
        precondition(skipped == 2)

        let empty: [Tile] = []
        precondition(uniqueFirst(empty, by: { $0 }).isEmpty)
        precondition(
            uniqueFirst([input[0], input[0]], by: { $0 })
                == [input[0]]
        )

        let byShape = uniqueFirst(input, by: { $0.shape })
        precondition(byShape == [input[0], input[1]])
        let shapeTotal = byShape.reduce(0) { $0 + $1.size }
        precondition(shapeTotal == 20)

        for tile in retained {
            print("\(tile.shape): \(tile.size)")
        }
        print("Total: \(total)")
        print("Skipped duplicates: \(skipped)")
        print("Shape-only total: \(shapeTotal)")
    }
}

No diretório do pacote, execute:

swift run OrderDemo

A saída esperada do programa, após eventuais mensagens de compilação, é mostrada abaixo. O programa foi conferido com base na documentação da API consultada, mas não foi executado aqui porque este ambiente de pesquisa não tem um executável do Swift.

circle: 12
square: 8
circle: 20
Total: 40
Skipped duplicates: 2
Shape-only total: 20

Por que a abordagem com array e conjunto preserva a ordem?

O array é a única fonte da ordem de saída. O loop percorre cada posição de entrada em sequência, e append(_:) coloca no final do resultado um valor aceito. O conjunto serve apenas para verificar se a chave selecionada já apareceu; o programa nunca o percorre.

A expressão crucial é seen.insert(key(value)).inserted. O Swift documenta que insert(_:) retorna inserted como true para um novo elemento e false quando já existe um elemento igual. Um elemento existente permanece inalterado. Esse valor de retorno permite que uma única operação decida se o valor original deve ser acrescentado. Consulte a documentação de inserção em Set da Apple.

Para a entrada fornecida, o primeiro círculo e o primeiro quadrado são aceitos. O segundo círculo idêntico é ignorado. O círculo maior é aceito porque seu valor completo é diferente, e o quadrado repetido é ignorado. Portanto, os tamanhos mantidos são 12 + 8 + 20 = 40.

A implementação mantém um invariante útil: após cada iteração, o resultado contém exatamente o valor encontrado primeiro para cada chave em seen, na ordem em que foram encontrados. Uma nova chave amplia as duas coleções; uma chave repetida não altera nenhuma delas. Esse raciocínio explica a garantia de ordenação independentemente de como o conjunto armazena seus elementos.

Como valores Swift personalizados devem expressar igualdade?

A declaração struct Tile: Hashable solicita conformidade sintetizada. As duas propriedades armazenadas, String e Int, podem ser hashable, então o Swift pode sintetizar o comportamento necessário. A Apple documenta essas condições para síntese em Hashable.

Usar { $0 } como chave faz com que o valor Tile inteiro determine a unicidade. Usar { $0.shape } muda o contrato para uma entrada mantida por forma. No exemplo, isso remove o círculo posterior de tamanho 20, reduzindo o total para 20. Trata-se de uma comparação intencional entre duas regras, não de uma segunda implementação da mesma regra.

Mantenha a seleção da chave determinística durante todo o cálculo. Derive-a do valor que está sendo processado, em vez de usar um contador ou uma variável externa que muda. Caso contrário, entradas iguais podem receber chaves diferentes e permanecer como entradas separadas.

Se você implementar igualdade e hashing manualmente, use as mesmas propriedades essenciais em ambos. A Apple exige que instâncias iguais forneçam os mesmos valores ao hasher e na mesma ordem. Evite usar hashValue em si como chave de unicidade: um hash não substitui o contrato de igualdade do valor. Manter a chave hashable real permite que o conjunto aplique esse contrato. Consulte os requisitos de conformidade de Hashable.

Quando você deve usar uma coleção ordenada?

Para este único cálculo, um array e um conjunto local deixam o comportamento explícito. Se um aplicativo acrescenta, remove, reordena e consulta repetidamente elementos únicos, uma coleção ordenada dedicada pode facilitar a manutenção dessas operações.

Opção Condição adequada Limite relevante
Array e conjunto Uma passagem por valores Swift sintéticos, possivelmente usando uma chave selecionada Sua função define o comportamento da primeira ocorrência
Swift Collections OrderedSet Uso contínuo de uma coleção ordenada de valores hashable únicos Requer o pacote separado Swift Collections
Foundation NSOrderedSet Uma API já trabalha com coleções ordenadas de objetos do Foundation Uma classe que representa uma coleção ordenada estática; operações mutáveis usam NSMutableOrderedSet

A documentação oficial do Swift Collections descreve OrderedSet como uma coleção ordenada de elementos únicos, importada por meio de OrderedCollections. Ela oferece operações que levam em conta a posição, como append(_:) e insert(_:at:). Essas são APIs do pacote, então adicionar apenas import OrderedCollections não configura um projeto que, de outra forma, não tem dependências. Consulte OrderedSet.

A documentação do Foundation da Apple descreve NSOrderedSet como uma coleção ordenada estática de objetos distintos e identifica NSMutableOrderedSet como sua versão mutável. Para o cálculo com valores Swift nativos acima, a função genérica expressa diretamente a chave de igualdade escolhida sem introduzir essa coleção de objetos. Consulte NSOrderedSet.

O que muda quando o cálculo alimenta uma interface de desktop?

O exemplo completo é síncrono e mantém suas coleções temporárias dentro da função. Para uma pequena lista sintética, isso proporciona uma ordem de processamento clara sem introduzir tarefas.

Em uma interface do macOS, isole adequadamente o estado e as atualizações voltados à interface. A Apple documenta MainActor como um ator global cujo executor equivale à fila principal de despacho; o guia de concorrência do Swift explica como aplicar @MainActor a funções e tipos que acessam o estado da interface. Consulte MainActor e Concurrency.

A concorrência também exige uma definição explícita de ordem. O Swift não garante a ordem de conclusão das tarefas filhas em um grupo de tarefas. Portanto, acrescentar resultados à medida que as tarefas terminam preserva a ordem de conclusão, que pode ser diferente da ordem original de entrada. O guia oficial de concorrência documenta esse limite.

Se uma versão futura executar cálculos sintéticos independentes em paralelo, associe cada posição de entrada ao respectivo resultado, restaure a ordem das posições de entrada após coletá-los e então aplique a passagem de unicidade. Esse projeto decorre do limite documentado para a ordem de conclusão. Mantenha o exemplo atual pequeno e síncrono, a menos que trabalho adicional justifique a coordenação extra.

Confira o contrato antes de reutilizar a função

O programa inclui verificações da ordem exata mantida, de uma entrada vazia, de valores idênticos repetidos e da regra alternativa que considera apenas a forma. Essas verificações se concentram nas decisões com maior probabilidade de alterar o significado do cálculo.

Ao adaptá-lo, confira três condições: a entrada já deve ter uma ordem significativa, a chave deve expressar a regra de igualdade pretendida e manter a primeira ocorrência deve ser apropriado. A função ignora deliberadamente as entradas posteriores que correspondem à primeira; ela não combina seus tamanhos nem substitui o valor mantido. A contagem de duplicatas ignoradas deixa esse efeito visível.

Para a lista sintética de formas fornecida, o resultado final contém três valores na ordem da primeira ocorrência e um total de 40. Deixe o array cuidar da ordem, o conjunto cuidar da pertinência e a chave selecionada definir o que significa “único”.

Fontes