Enumerar uma matriz, agrupando duplicatas


24

O objetivo deste desafio é pegar uma matriz de números inteiros positivos e enumerar seus índices, agrupando como elementos.

Uma enumeração sem duplicatas é feita apenas com a saída de uma matriz de pares (value, index), por exemplo, [3, 4, 13, 9, 2]=> [[3,1],[4,2],[13,3],[9,4],[2,5]].

No entanto, se um determinado elemento aparecer pela segunda vez, ele não recebe seu próprio par, mas é adicionado ao grupo de sua primeira ocorrência. Se, no exemplo acima, substituímos o 9 por 3, na saída removemos [9,4]e substituímos [3,1]por [3,1,4].

Na saída, os grupos devem ser ordenados pela primeira ocorrência e os índices devem estar em ordem crescente. O elemento deve ser o primeiro em um grupo, antes de seus índices. A saída pode ser 0 ou 1 indexada. Você pode assumir que a matriz possui pelo menos um elemento.

Casos de teste:

Input           | Output (One-indexed)
[3, 2, 2, 3]    | [[3, 1, 4], [2, 2, 3]]
[17]            | [[17, 1]]
[1, 1]          | [[1, 1, 2]]
[1, 1, 2]       | [[1, 1, 2], [2, 3]]
[1, 2, 3, 4]    | [[1, 1], [2, 2], [3, 3], [4, 4]]
[1, 1, 1, 1]    | [[1, 1, 2, 3, 4]]

Isso é , o menor número de bytes vence!


Seria aceitável que os indides fossem produzidos como strings, por exemplo [[17,"1"]]? (Ainda não sei se eu posso salvar qualquer bytes que forma, ainda trabalhando nisso!)
Shaggy

@shaggy certeza, tudo bem
Pavel


11
Podemos produzir algo parecido [[3, [1, 4]], [2, [2, 3]]]?
Conor O'Brien

11
@Pavel isso não é motivo: p mas com certeza
Conor O'Brien

Respostas:


9

Dyalog APL, 5 bytes

(⊂,)⌸

Experimente online!

,⌸para 2 bytes quase funciona, mas possui zeros à direita: /


O que no mundo faz ?
Mr. Xcoder

@ Mr.Xcoder recebe os índices de cada coisa e chama o operador esquerdo com a coisa e os índices de onde ela existe
dzaima

Como o isue com ,⌸está arrastando os zeros e os zeros nunca estarão na entrada, seria possível eliminar todos os zeros em menos de 3 bytes?
Pavel

@ Pavel, a razão pela qual existem zeros é que o resultado é uma matriz, que precisa ter dimensões exatas; portanto, há apenas 1 byte para eliminar os zeros para qualquer ganho de byte. Eu sinto que isso pode ser jogável no entanto.
Dzaima 19/0118

2
Formato de saída do array "fancy af" : Experimente online!
Adám

7

J , 12 bytes

~.,&.><@I.@=

Indexado a zero.

Experimente online!

Se você puder remover todo o trabalho que estou fazendo com caixas, provavelmente poderá reduzir bastante o número de bytes. Vou ver se consigo descobrir isso.

Explicação

Provavelmente é muito cedo para explicar (deve haver mais campos de golfe).

~. ,&.> <@I.@=
             =  Self-classify (comparison of each unique element to array)
            @   Composed with
          I.    Indices of ones (where it's equal)
         @      Composed with
        <       Boxed (how we deal with arrays of unequal length)
   ,&.>         Joined with
      >          Unbox each
   ,             Concatenate
    &.           Box again
~.              Unique elements

2
Esse formato de saída de matriz é chique af
Pavel

@Pavel também é tomando um monte de bytes Π.Π
cole

5

05AB1E , 10 bytes

ÙεDIQƶ0K)˜

Experimente online!

Explicação

Ù             # remove duplicates
 ε            # apply to each element
  D           # duplicate
   IQ         # compare for equality with input
     ƶ        # multiply each element by its index (1-based)
      0K      # remove zeroes
        )˜    # wrap in a flattened list



5

Anexo , 15 bytes

Flat=>Positions

Experimente online!

Este é um caso interessante de =>, a forma de operador de Map. Quando recebem dois argumentos funcionais fe g, Mapretorna uma função f => g[x]over x. Ou seja, o RHS é aplicado à entrada e, em seguida, o LHS é mapeado.

O built-in Positionsgera uma matriz que representa o agrupamento de entradas por índices. Por padrão, quando não fornecido com um segundo argumento, Positionsusará o primeiro argumento. Flaté então mapeado sobre cada item, pois é isso que a pergunta exige.

Soluções alternativas

31 bytes

MapArgs[Concat#~Indices,Unique]

Experimente online!

Uma alternativa bastante curta e sem componentes. MapArgsé uma função como Map, exceto que você pode alimentar argumentos extras nela. Por exemplo, MapArgs[{_1 + _2}, 1..3, 3]é [4, 5, 6]. Como Map, torna-se curry quando fornecido com dois argumentos funcionais. A função a ser mapeada é Concat#~Indices, que é uma bifurcação. Este fork é aplicado aos Uniqueitens da entrada e da própria entrada. Isso se traduz em Concat[_, Indices[_2, _]](com os argumentos de Indicesswapped through ~), que emparelha o elemento que está sendo mapeado ( _) com os índices do referido elemento _na matriz de entrada, que é _2(como ffed through MapArgs).

43 bytes

{Flat=>Zip[Unique[_],Indices[_,Unique[_]]]}

Experimente online!

Esta é realmente apenas uma combinação mais detalhada (ainda que um pouco mais legível) das soluções 1 e 2.


4

Gelatina , 6 bytes

Q;"ĠṢ$

Experimente online!

Explicação:

Q;"ĠṢ$
Q      Keep the first occurrence of each element
     $ Last two links as a monad
   Ġ    Group indices of equal elements, then sort the resulting list of groups by the element they point to
    Ṣ   Sort; used to re-order the list of groups based on first occurrence instead
  "    Vectorize link between two arguments (the first occurrences and the group list)
 ;      Concatenate

Não funciona para o último caso de teste . A matriz deve ser aninhada em outra camada, a saída é sempre bidimensional.
Pavel

@Pavel sim ele faz , eu só esqueceu de adicionar um rodapé (resposta é uma função)
Erik o Outgolfer

Ok então legal. Explicação em breve, sim? : P
Pavel

@Pavel adicionou explicações
Erik the Outgolfer

4

Pitão , 7 bytes

Indexado a 0.

{+VQxRQ

Experimente aqui! Alternativo.

Quão?

{+ VQxRQ - Programa completo.

     RQ - Para cada elemento ...
    x - Obtenha todos os seus índices.
 + V - E aplique concatenação vetorizada.
   Q - Com a entrada.
{- Desduplicar.

4

MATL , 8 bytes

u"@tG=fh

Experimente no MATL Online

Explicação

        # Implicitly get the input
u       # Compute the unique values
"       # For each unique value, N
  @     # Push the value N to the stack
  t     # Duplicate N
  G     # Grab the input
  =f    # Get the 1-based indices of the elements that equal N
  h     # Horizontally concatenate N with the indices
        # Implicitly display the result

ooooohhh isso é inteligente! Eu tinha 18 bytes tentando usar, &fmas nunca consegui funcionar.
Giuseppe

3

Na verdade , 24 bytes

;;╗⌠╝╜r⌠╜E╛=⌡░⌡M@Z⌠♂i⌡M╔

Experimente online!

Explicação:

;;╗⌠╝╜r⌠╜E╛=⌡░⌡M@Z⌠♂i⌡M╔
;;                        make two copies of input
  ╗                       save a copy to register 0
   ⌠╝╜r⌠╜E╛=⌡░⌡M          map over input:
    ╝                       save the element in register 1
     ╜r                     indices for input
       ⌠╜E╛=⌡░              filter:
        ╜E                    element in input at index
          ╛=                  equals element for outer map (from register 1)
                @Z        swap, zip input with map result
                  ⌠♂i⌡M   flatten each element in zipped list
                       ╔  uniquify

3

R , 56 bytes

function(x)lapply(unique(x),function(y)c(y,which(x==y)))

Experimente online!


Esta é minha primeira tentativa de codegolf, então qualquer feedback é bem-vindo!


3
Bem-vindo ao PPCG! Ótima primeira resposta.
Pavel

11
Olá Florian! Resposta muito boa. Na verdade, trata-se de um trecho de código em vez de um programa ou função - assume que a entrada está codificada x, mas deve haver uma maneira de ler a entrada - normalmente usamos scanou definimos uma função. Além disso, ele precisa ser produzido, portanto, é necessário envolvê-lo em a printou a cat.
Giuseppe

11
veja esta questão para mais truques calhar R golfe :)
Giuseppe

11
Obrigado rapazes! E o link para as dicas r é certamente útil!
Florian

2
@ Florian R não é tão ruim quanto você pensa (exceto em desafios de cordas ...), desde que você se lembre de que está jogando golfe contra outros jogadores R! Sinta-se à vontade para me enviar um ping no bate-papo, se tiver alguma dúvida. Há alguns jogadores de R ativos, que definitivamente oferecem sugestões e também apreciam a sua! Bem-vindo ao golfe :)
Giuseppe


3

JavaScript (ES6), 64 bytes

0 indexado

a=>a.map((v,i)=>a[-v]?a[-v].push(i):a[-v]=[v,i]).filter(x=>x[0])

Observe que isso pressupõe que os números de entrada sejam positivos; portanto, v> 0

Teste ligeiramente modificado (1 indexado) para corresponder aos casos de teste

var F=
a=>a.map((v,i)=>a[-v]?a[-v].push(i+1):a[-v]=[v,i+1]).filter(x=>x[0])

test = [ // output 1 indexed
  [3, 2, 2, 3],//    | [[3, 1, 4], [2, 2, 3]]
  [17], //           | [[17, 1]]
  [1, 1], //         | [[1, 1, 2]]
  [1, 1, 2], //      | [[1, 1, 2], [2, 3]]
  [1, 2, 3, 4], //   | [[1, 1], [2, 2], [3, 3], [4, 4]]
  [1, 1, 1, 1] //    | [[1, 1, 2, 3, 4]] 
]

test.forEach(t => {
  x = F(t)
  console.log(JSON.stringify(t)+ ' -> ' + JSON.stringify(x))
})


3

NARS APL, 24 bytes, 12 caracteres

{∪⍵,¨⍸¨⍵=⊂⍵}

-4 bytes graças ao teste de Adam:

  f←{∪⍵,¨⍸¨⍵=⊂⍵}

  ⎕fmt f 3 2 2 3
┌2────────────────┐
│┌3─────┐ ┌3─────┐│
││ 3 1 4│ │ 2 2 3││
│└~─────┘ └~─────┘2
└∊────────────────┘
  ⎕fmt f 17
┌1──────┐
│┌2────┐│
││ 17 1││
│└~────┘2
└∊──────┘
  ⎕fmt f 1 1
┌1───────┐
│┌3─────┐│
││ 1 1 2││
│└~─────┘2
└∊───────┘
  ⎕fmt f 1 2 3 4
┌4──────────────────────────┐
│┌2───┐ ┌2───┐ ┌2───┐ ┌2───┐│
││ 1 1│ │ 2 2│ │ 3 3│ │ 4 4││
│└~───┘ └~───┘ └~───┘ └~───┘2
└∊──────────────────────────┘
  ⎕fmt f 1 1 1 1
┌1───────────┐
│┌5─────────┐│
││ 1 1 2 3 4││
│└~─────────┘2
└∊───────────┘

Shave a 4 bytes / 2 chars:{∪⍵,¨⍸¨⍵=⊂⍵}
Adám

3

SWI-Prolog , 165 117 bytes

-48 bytes graças às dicas de golfe do Prolog .

h(I):-I+[]-1.
[H|T]+R-N:-(select([H|A],R,[H|L],S),!,append(A,[N],L);append(R,[[H,N]],S)),O is N+1,(T+S-O,!;write(S)).

Experimente online!

Explicação

% The predicate that prints the grouped duplicates. It's a wrapper because we
% need some extra arguments to keep state:
enumerate_duplicates(Input) :- enumerate(Input, [], 1).

% In the golfed code, operators are used to represent this predicate.
% See /codegolf//a/153160
% Go through the input, build up the result on the way and print it.
enumerate([Head|Tail], Result, Index) :-
    (
        % If our current Result already contains a list that starts with the
        % current first element in our input, Head, NewIndexes will become the
        % new "tail" of that list in our next result list:
        select([Head|OldIndexes], Result, [Head|NewIndexes], NextResult),
        % Don't backtrack before this if goals below this fail:
        !,
        % The as-yet-unknown NewIndexes above should in fact be the same as
        % OldIndexes with our current Index appended:
        append(OldIndexes, [Index], NewIndexes)
    % Use ; instead of separate predicate rules.
    % See /codegolf//a/67032
    ;
        % If our current Result did not already contain Head, append a new list
        % for it with the current index:
        append(Result, [[Head, Index]], NextResult)
    ),
    % Increment our index counter:
    NextIndex is Index + 1,
    (
        % And continue with the rest of our input:
        enumerate(Tail, NextResult, NextIndex),
        % Don't backtrack if the above succeeded:
        !
    ;
        % If Tail is no longer a multi-element list, we're done. Print:
        write(NextResult)
    ).

3

K (oK) , 10 bytes

Solução:

(!x),'.x:=

Experimente online!

Exemplos:

(!x),'.x:=,17
,17 0
(!x),'.x:=1 1
,1 1 2
(!x),'.x:=1 0 1
(1 1 2
2 3)
(!x),'.x:=1 2 3 4
(1 0
2 1
3 2
4 3)

Explicação:

A avaliação é realizada da direita para a esquerda. Eu ainda acho que isso é capaz de golfe ainda mais ...

(!x),'.x:= / the solution
         = / group input into dictionary, item!indices
       x:  / save as variable x
      .    / value of x (the indices)
    ,'     / concatenate (,) each-both (') with
(  )       / do this together
 !x        / the key of x (i.e. the items)

Notas:

  • 14 bytes sem declarar x, (,/)'+(!;.)@'=, deu-se com esta abordagem ...

11
Você pode retornar um resultado indexado em 0, então acho que pode pular o 1+.
Adám


2

JavaScript (ES6), 68 bytes

Indexado a 0.

a=>a.map(p=(x,i)=>1/p[x]?b[p[x]].push(i):b.push([x,p[x]=i]),b=[])&&b

Casos de teste


Números de entrada são = 0, que poderia ser útil para evitar o 1 / x truque!
edc65

2

PHP 4.1, 88 bytes

Sim, é bem longo.

Isso pressupõe um arquivo padrão php.ini ( short_open_tag = One register_globals = On).

<?foreach($A as$k=>$v){!$b[$v]&&$b[$v]=array($v);$b[$v][]=$k;}print_r(array_values($b));

Isso apresenta a matriz de uma maneira legível por humanos.
Os valores podem ser passados ​​por POST, GET e COOKIE, dentro da tecla "A".


Para uma versão moderna, pode-se usar (90 bytes):

<?foreach($_GET[A]as$k=>$v){if(!$b[$v])$b[$v]=[$v];$b[$v][]=$k;}print_r(array_values($b));

O resultado é o mesmo, exceto que todos os valores devem ser passados ​​sobre os parâmetros GET dentro da chave "A".


2

Perl 6 ,  63  61 bytes

*.pairs.classify(*.value).map({.key,|.value».key}).sort(*.[1])

Teste (baseado em 0)

{sort *.[1],map {.key,|.value».key},classify *.value,.pairs}

Teste (mesmo algoritmo baseado em 0)

Expandido:

# WhateverCode lambda (this is the parameter) 
*\                                            # [3,2,2,3]

# get a list of Pairs (zero based index => value)
.pairs                                        # (0=>3,1=>2,2=>2,3=>3)

# classify based on the values (unordered result)
.classify(*.value)                            # {2=>[1=>2,2=>2],3=>[0=>3,3=>3]}

# simplify the structure
.map({
  .key,         # the value
  |.value».key  # slip in the indexes
})                                            # ((3,0,3),(2,1,2))

# sort based on first index
.sort(*.[1])

2

Japonês , 14 9 bytes

Indexado a 0.

â £ð¶X iX

Tente

â £ð¶X iX
â             :Deduplicate
  £           :Map each X
   ð          :  Get 0-based indices of elements in the input
    ¶X        :    That are equal to X
       iX     :  Prepend X

2

PHP 7.4 ou superior , 71 bytes

* 73 bytes para citar a $_GETchave e evitar avisos.

Snippet: ( demonstração )

<?foreach($_GET[A]as$k=>$v){$b[$v][0]=$v;$b[$v][]=$k;}print_r([...$b]);

Com base no representante, presumo que o IsmaelMiguel saiba a melhor maneira de postar código php nessa comunidade, então estou construindo a partir de sua fundação . Não está claro para mim se <?deve ser incluído / contado no meu snippet . Como este é o meu primeiro post, fico feliz que alguém explique se existe alguma sintaxe desnecessária. ps Também li Dicas para jogar golfe em PHP, o que me parece um ótimo candidato à migração para o Meta .

As melhorias feitas no snippet de Ismael são:

  1. Atribuição incondicional do primeiro elemento em cada sub-matriz (substituição de valor)
  2. Embalagem em splat em vez dearray_values() reindexar a saída.


1

Kotlin , 83 bytes

{it.mapIndexed{i,c->c to i}.groupBy({(a,b)->a},{(a,b)->b}).map{(a,b)->listOf(a)+b}}

Embelezado

{
    it.mapIndexed { i, c -> c to i }
        .groupBy({ (a, b) -> a }, { (a, b) -> b })
        .map { (a, b) -> listOf(a) + b }
}

Teste

var f: (List<Int>) -> List<List<Int>> =
{it.mapIndexed{i,c->c to i}.groupBy({(a,b)->a},{(a,b)->b}).map{(a,b)->listOf(a)+b}}

data class Test(val input: List<Int>, val output: List<List<Int>>)

val tests = listOf(
        Test(listOf(3, 2, 2, 3), listOf(listOf(3, 0, 3), listOf(2, 1, 2))),
        Test(listOf(17), listOf(listOf(17, 0))),
        Test(listOf(1, 1), listOf(listOf(1, 0, 1))),
        Test(listOf(1, 1, 2), listOf(listOf(1, 0, 1), listOf(2, 2))),
        Test(listOf(1, 2, 3, 4), listOf(listOf(1, 0), listOf(2, 1), listOf(3, 2), listOf(4, 3))),
        Test(listOf(1, 1, 1, 1), listOf(listOf(1, 0, 1, 2, 3)))
)

fun main(args: Array<String>) {
    for (c in tests) {
        val o = f(c.input)
        if (o != c.output) {
            throw AssertionError("${c.input} -> $o != ${c.output}")
        }
    }
}

TIO

TryItOnline


Essa solução é um trecho, não uma função ou programa completo. Requer que a variável iseja predefinida. Você pode validar isso convertendo-o em um lambda que aceita um parâmetro i.
Pavel

Reformulado para resolver questão levantada pelo @Pavel
jrtapsell

1

Swift 4, 107 bytes

... Caramba.

{a in Dictionary(grouping:a.enumerated()){$0.1}.sorted{$0.1.first!.0<$1.1.first!.0}.map{[$0]+$1.flatMap{$0.0}}}

Ungolfed:

let f = { (input: [Int]) -> [[Int]] in
    return Dictionary(grouping: input.enumerated(), by: { $0.element })
        .sorted { pairA, pairB in // Sort by order of first appearence (lowest offset)
            return pairA.value.first!.offset < pairB.value.first!.offset
        }.map { element, pairs in
            return [element] + pairs.map{ $0.offset /* +1 */} // add 1 here for 1 based indexing
        }
}

É uma pena que o dicionário perca a ordem, forçando-me a desperdiçar tantos caracteres ao classificar novamente. Este tipo de abuso de argumentos de fechamento implícitos ( $0, $1...) e os membros tupla implícitos ( .0, .1...) é uhhhhh não é bonito.



1

Ruby , 54 52 bytes

->a{a.map{|i|[i]+(0..a.size).select{|j|a[j]==i}}|[]}

Esta versão permite zero (53 bytes):

->a{a.map{|i|[i]+(0...a.size).select{|j|a[j]==i}}|[]}

Experimente online!


O desafio especifica que a matriz conterá apenas números inteiros positivos e haverá pelo menos um elemento. nilnão é um número inteiro positivo.
Pavel

@Pavel graças, eu verifiquei, mas perdeu-o de alguma forma
asone Tuhid
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.