Agrupar uma lista por frequência


26

Dada uma lista de números inteiros, agrupe os elementos que ocorrem mais primeiro, depois agrupe os seguintes e assim sucessivamente até que cada elemento exclusivo da lista tenha sido agrupado uma vez.


Exemplos:

Entrada: [1,2,3]

Saída: [[1,2,3]]


Entrada: [1,1,1,2,2,3,3,4,5,6]

Saída: [[1],[2,3],[4,5,6]]


Entrada: [1,1,1,4,5,6,6,6,7,7,8,8,8,8,8,8,8,9,5,6,5,6,5,6,5,6,-56]

Saída: [[6, 8],[5],[1],[7],[9,4,-56]]


Entrada: []

Saída: []


Entrada: (empty input)

Saída: ERROR/Undefined/Doesn't matter


Regras

  • Os agrupamentos devem passar da frequência máxima para a frequência mínima.
  • A ordem interna dos agrupamentos é arbitrária (o exemplo 3 do EG 3 poderia ter [8,6]).
  • Isso é , vitórias mais baixas na contagem de bytes.

Relacionado


1
A saída pode estar no formato de string? Ou seja. Uma lista de listas, mas cada número representado por um caractere em vez de um número inteiro.
mb7744

Respostas:



7

Mathematica, 43 bytes

Union/@SortBy[l=#,f=-l~Count~#&]~SplitBy~f&

Experimente online! (Usando matemática.)

Alternativamente:

SortBy[Union[l=#],f=-l~Count~#&]~SplitBy~f&

5
Não há embutido?
Magic Octopus Urn

É GatherByuma opção, não tenho certeza, porque eu não sei o idioma.
Magic Octopus Urn

1
@carusocomputing Ele classifica os grupos pela primeira ocorrência dos elementos na lista original, então eu ainda teria que classificar os grupos posteriormente. Classificando a lista primeiro, posso salvar um byte com SplitBy(também SortByseria realmente mais complicado se o fizesse GatherByprimeiro).
Martin Ender

Interessante, então o "deve estar em ordem do máximo ao mínimo" estraga tudo isso?
Magic Octopus Urn

@carusocomputing Exatamente.
Martin Ender

5

Python 2 , 145 141 bytes

import collections as c,itertools as i;o=lambda n:lambda l:l[n]
print[map(o(0),g)for _,g in i.groupby(c.Counter(input()).most_common(),o(1))]

Experimente online!

Esta é a minha primeira submissão depois de anos de leitura.

Basicamente, ele coloca todos os elementos em um contador (dicionário de quantos de cada elemento da lista) e .most_common () coloca os itens em ordem decrescente de frequência. Depois disso, é apenas uma questão de formatar os itens na lista correta.

Guardado 4 bytes graças a ovs .


4
Bem-vindo ao PPCG :). Não fique tão viciado quanto eu.
Magic Octopus Urn

A criação de sua própria função itemgetter é 4 bytes menor do que a importação:o=lambda n:lambda l:l[n]
ovs 13/06

5

JavaScript (ES6), 95 101 bytes

a=>a.map(x=>(o[a.map(y=>n+=x!=y,n=0)|n]=o[n]||[])[x*x+(x>0)]=x,o=[])&&(F=o=>o.filter(a=>a))(o).map(F)

Quão?

Para cada elemento x da matriz de entrada a , calculamos o número n de elementos de a que são diferentes de x :

a.map(y => n += x != y, n = 0) | n

Nós usamos os índices n e x para preencher a matriz o :

(o[n] = o[n] || [])[x * x + (x > 0)] = x

Edit : Como o JS não suporta índices de matriz negativos, precisamos da fórmula x * x + (x > 0)para forçar índices positivos.

Isso nos fornece uma matriz de matrizes contendo os elementos exclusivos da lista original, agrupados por frequência e ordenados da mais frequente para a menos frequente.

No entanto, tanto a matriz externa quanto a matriz interna possuem potencialmente muitos slots vazios que queremos filtrar. Fazemos isso com a função F , aplicada a o e cada um de seus elementos:

F = o => o.filter(a => a)

Casos de teste


Eu acho que um Setpoupa um byte: a=>a.map(e=>(r[n=0,a.map(f=>n+=e!=f),n]||(r[n]=new Set)).add(e),r=[])&&r.filter(s=>s).map(s=>[...s]).
Neil

@ Neil Isso é bem diferente da minha abordagem atual. Talvez você deva postar como uma nova resposta?
precisa

Eu não achei que mudar o[n]de um array para um set fosse tão diferente, mas eu já joguei a resposta de @ RickHitchcock de qualquer maneira, então não há muito sentido.
Neil



2

Clojure, 74 bytes

#(for[[_ g](sort-by(comp - key)(group-by val(frequencies %)))](map key g))

Parece bastante detalhado: /


Bata em mim (e me bata em alguns bytes, uso inteligente de comp -para reverter!). Não tão curto quanto outras línguas, mas eu pensei que era divertido desde Clojure tem "grupo-by" e "frequências" Built in.
MattPutnam

Quando li a descrição da tarefa, esperava 50 ou 60 bytes, mas a implementação real acabou sendo um pouco mais complicada.
NikoNyrh

2

Perl 6 , 43 bytes

*.Bag.classify(-*.value).sort».value».key

Teste-o

Expandido:

*                   # WhateverCode lambda (this is the input)
                    # [1,1,1,2,2,3,3,4,5,6]

.Bag                # turn into a Bag
                    # (1=>3,5=>1,4=>1,3=>2,6=>1,2=>2).Bag

.classify(-*.value) # classify by how many times each was seen
                    # {-2=>[3=>2,2=>2],-3=>[1=>3],-1=>[5=>1,4=>1,6=>1]}

.sort\              # sort (this is why the above is negative)
                    # {-3=>[1=>3],-2=>[3=>2,2=>2],-1=>[5=>1,4=>1,6=>1]}

».value\            # throw out the classification
                    # ([1=>3],[3=>2,2=>2],[5=>1,4=>1,6=>1])

».key               # throw out the counts
                    # ([1],[3,2],[5,4,6])

Uau, eu sempre esqueço Bag, bom!
Magic Octopus Urn

2

Utilitários Bash + GNU, 71 61

sort|uniq -c|sort -nr|awk '{printf$1-a?"\n%d":",%d",$2;a=$1}'

Entrada como uma lista delimitada por nova linha. Saída como uma lista delimitada por nova linha de valores separados por vírgula.

Experimente online .


2

MATL , 9 bytes

9B#uw3XQP

Entrada é um vetor de coluna, usando ;como separador.

Experimente online!

Explicação

9B#u   % Call 'unique' function with first and fourth outputs: unique entries and
       % number of occurrences
w      % Swap
3XQ    % Call 'accumarray' with anonymous function @(x){sort(x).'}. The output is
       % a cell array with the elements of the input grouped by their frequency.
       % Cells are sorted by increasing frequency. Some cells may be empty, but
       % those won't be displayed
P      % Flip cell array, so that groups with higher frequency appear first.
       % Implicitly display

2

k, 22 bytes

{x@!x}{(>x)@=x@>x}#:'=

Experimente online.

( O k de AW parece exigir um extra @antes do #, mas oK não.)

Explicação:

                     = /group identical numbers in a map/dict
                  #:'  /get number of times each number is repeated
                       /this is almost the answer, but without the inner lists
      {      x@>x}     /order "number of times" greatest to least
            =          /group them (to make the smaller groups)
       (>x)@           /get the actual numbers into place
{x@!x}                 /get values of the map/dict it's in

github.com/JohnEarnest/ok para mais alguém se perguntando o que ké, na verdade ok. -Ba-dum Tssss ...
Magia Octopus Urna

2

Braquilog , 10 bytes

ọtᵒ¹tᵍhᵐ²|

Experimente online!

Explicação

Example input: [2,1,1,3]

ọ            Occurences:            [[2,1],[1,2],[3,1]]
 tᵒ¹         Order desc. by tail:   [[1,2],[3,1],[2,1]]
    tᵍ       Group by tail:         [[[1,2]],[[3,1],[2,1]]]
      hᵐ²    Map twice head:        [[1],[3,2]]

         |   Else (Input = [])      Input = Output

2

Mathematica, 79 bytes

Table[#&@@@f[[i]],{i,Length[f=GatherBy[Sort[Tally@#,#1[[2]]>#2[[2]]&],Last]]}]&

entrada

[{1, 1, 1, 4, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 9, 5, 6, 5, 6, 5, 6, 5, 6, -56}]

saída

{{8, 6}, {5}, {1}, {7}, {-56, 9, 4}}


O GatherBy que eu mencionei para Martin! Eu me perguntava como isso seria feito :).
Magic Octopus Urn

Sort[...,...&]é justo SortBy[...,-Last@#&].
Martin Ender

Length[f=...]. E First/@é #&@@@.
Martin Ender

fixo, fixo e fixo
J42161217

2

R , 84 77 bytes

-7 bytes graças a mb7744

unique(lapply(x<-sort(table(scan()),T),function(y)as.double(names(x[x==y]))))

Lê de stdin; retorna uma lista com subvetores de números inteiros em ordem crescente. Se pudéssemos retornar strings em vez de ints, eu poderia eliminar 11 bytes (removendo a chamada para as.double), mas é isso. A tablefunção de R faz o trabalho pesado aqui, contando as ocorrências de cada membro de sua entrada; depois os agrega por count ( names). Claro, isso é uma string, então temos que coagi-la a um número inteiro / duplo.

Experimente online!


Você pode perder 7 bytes, eliminando o "qual" e usando a indexação lógica
mb7744

@ mb7744 oh duh.
21417 Giuseppe #:

1
Fiz outra tentativa com R. É lamentável quanto tempo a sintaxe lambda é, então resolvi evitá-la. Em troca, tive que usar aninhados lapply, mas pelo menos nesse caso, posso atribuir uma variável curta a lapply. Eu não consigo atribuir uma variável para a função function...
mb7744

2

JavaScript (ES6), 100 98 96 93 bytes

Economizei 2 bytes graças a @Neil (além disso, ele corrigiu um erro de borda no meu código). Economizou mais 3 bytes graças a @TomasLangkaas.

a=>a.sort().map((_,n)=>a.filter((v,i)=>i-a.indexOf(v)==n&v!=a[i+1])).filter(a=>a+a).reverse()

Casos de teste

f=
a=>a.sort().map((_,n)=>a.filter((v,i)=>i-a.indexOf(v)==n&v!=a[i+1])).filter(a=>a+a).reverse()

console.log(JSON.stringify(f([1,2,3])))
console.log(JSON.stringify(f([1,1,1,2,2,3,3,4,5,6])))
console.log(JSON.stringify(f([1,1,1,4,5,6,6,6,7,7,8,8,8,8,8,8,8,9,5,6,5,6,5,6,5,6,-56])))
console.log(JSON.stringify(f([])))


Seu teste é falho (não funciona para zero), mas eu acho que você ainda pode salvar bytes, filtrando e reverter em vez de unshifting: a=>a.sort().map((_,n)=>a.filter((v,i)=>i-a.indexOf(v)==n&v!=a[i+1])).filter(a=>1/a[0]).reverse().
Neil

Ahh, eu deveria saber testar 0! Seu código o corrige, além de ser mais curto, então obrigado por isso
:)

Salve mais 3 bytes alterando .filter(a=>1/a[0])para .filter(a=>''+a).
Tomas Langkaas

Bom, @TomasLangkaas, obrigado. (Salva 2 bytes.)
Rick Hitchcock

Meu mau (tenho problemas com a contagem), mas .filter(a=>a+a)forneceria o byte extra.
Tomas Langkaas

1

V , 60 , 54 bytes

Úòͨ¼¾©î±/± ±òHòø 
pkJjòú!
Ǩ^ƒ ©î±/o
Îf ld|;D
òV{Jk

Experimente online!

Hexdump:

00000000: daf2 cda8 bc81 bea9 eeb1 2fb1 20b1 f248  ........../. ..H
00000010: f2f8 200a 706b 4a6a f2fa 210a c7a8 5e83  .. .pkJj..!...^.
00000020: 20a9 81ee b12f 6f0a ce66 206c 647c 3b44   ..../o..f ld|;D
00000030: 0af2 567b 4a6b                           ..V{Jk

Por mais que eu goste de V, tenho certeza de que esse é o pior idioma possível para a tarefa. Especialmente considerando que ele não tem suporte para listas e basicamente não suporta números. Apenas manipulação de cordas.


1

C #, 119 bytes

Apenas uma rápida facada:

using System.Linq;
a=>a.GroupBy(x=>x)
    .GroupBy(x=>x.Count(),x=>x.Key)
    .OrderBy(x=>-x.Key)
    .Select(x=>x.ToArray())
    .ToArray()

2
+1 Você pode remover o System.Func<int[],int[][]>F=e à direita ;. Isso não faz parte da contagem de bytes para esses tipos de lambdas.
Kevin Cruijssen

@KevinCruijssen, eu não fazia ideia. Obrigado!
Hand-E-Food

1

R , 66 bytes

(l=lapply)(l(split(x<-table(scan()),factor(-x)),names),as.integer)

Experimente online!

Se na saída os números inteiros podem estar no formato de string, pode cair para 48 bytes (como mencionado na resposta de @ Giuseppe).


Ungolfed:

input <- scan(); # read input
x <- table(input); # count how many times each integer appears, in a named vector
y <- split(x, factor(-x)) # split the count into lists in increasing order
z <- lapply(y, names) # access the the original values which are still
                      # attached via the names
lapply(z, as.integer) # convert the names back to integers

as.doubleé mais curto em um byte e deve funcionar da mesma forma queas.integer
Giuseppe

Bem, depende se você deseja retornar um número inteiro ou um dobro. Se double estiver correto, talvez o caractere também esteja, e nós dois poderíamos salvar alguns bytes.
mb7744

1

PowerShell, 77, 70 bytes

($a=$args)|group{($a-eq$_).count}|sort n* -Des|%{,($_.group|sort -u)}

NB: Para verificar se esses resultados estão agrupados corretamente (como visualmente não há delineamento entre o conteúdo de cada matriz), convém anexar | write-hostao final da linha acima.

Agradecimentos

Graças a:

  • TessellatingHeckler por economizar 7 bytes ao refatorar / reescrever massivamente para uma abordagem bem mais eficiente.

Anterior

77 bytes

param($x)$x|group|sort count -desc|group count|%{,($_.group|%{$_.group[0]})}

Bom obrigado. Eu tive que incluir o ,()agrupamento for (uma vez que a saída estava apenas aparecendo como uma matriz contínua). Isso é muito mais golfe do que minha tentativa original; otimo trabalho!
JohnLBevan

0

Groovy, 71 bytes

{a->a.groupBy{a.count(it)}.sort{-it.key}.values().collect{it.unique()}}

Na verdade, eu só aprendi sobre o groupBy depois de criar isso. Eu não sabia que colecionar não era minha única escolha.


{
    a->                 // [1,2,1,2,3,3,3,6,5,4]
    a.groupBy{      
        a.count(it)     // [2:[1,2,1,2],3:[3,3,3],1:[6,5,4]]
    }.sort{             
        -it.key         // [3:[3,3,3],2:[1,2,1,2],1:[6,5,4]]
    }.values().collect{ // [[3,3,3],[1,2,1,2],[6,5,4]]
        it.unique()
    }                   // [[3],[1,2],[6,5,4]]
}

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.