Enumerar una matriz, agrupando duplicados

24

El objetivo de este desafío es tomar una serie de enteros positivos y enumerar sus índices, agrupando elementos similares.

Una enumeración sin duplicados se realiza simplemente generando una matriz de pares (value, index), por ejemplo, [3, 4, 13, 9, 2]=> [[3,1],[4,2],[13,3],[9,4],[2,5]].

Sin embargo, si un elemento dado aparece por segunda vez, no se le da su propio par, sino que se agrega al grupo de su primera aparición. Si en nuestro ejemplo anterior reemplazamos el 9 con 3, entonces en la salida eliminaríamos [9,4]y reemplazaríamos [3,1]con [3,1,4].

En la salida, los grupos deben ordenarse por su primera aparición, y los índices deben estar en orden ascendente. El elemento debe estar primero en un grupo, antes de sus índices. La salida puede ser 0 o 1 indexada. Puede suponer que la matriz tiene al menos un elemento.

Casos de prueba:

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]]

Este es el , ¡la menor cantidad de bytes gana!

Pavel
fuente
¿Sería aceptable que los indides salieran como cadenas, por ejemplo [[17,"1"]]? (¡Aún no sé si puedo guardar los bytes de esa manera, aún trabajando en ello!)
Shaggy
@shaggy seguro, está bien
Pavel
3
Posible duplicado.
Totalmente humano el
1
¿Podemos generar algo como en su [[3, [1, 4]], [2, [2, 3]]]lugar?
Conor O'Brien
1
@Pavel esa no es razón: p pero seguro
Conor O'Brien

Respuestas:

9

Dyalog APL, 5 bytes

(⊂,)⌸

Pruébalo en línea!

,⌸para 2 bytes casi funciona, pero tiene ceros al final: /

dzaima
fuente
¿Qué hace el mundo ?
Sr. Xcoder
@ Mr.Xcoder obtiene los índices de cada cosa y llama al operador izquierdo con la cosa e índices donde existe
dzaima
Dado que el problema con ,⌸es ceros finales, y los ceros nunca estarán en la entrada, ¿sería posible eliminar todos los ceros en menos de 3 bytes?
Pavel
@Pavel, la razón por la que existen los ceros es que el resultado es una matriz, que tiene que tener dimensiones exactas, por lo que solo hay 1 byte para soltar los ceros para cualquier ganancia de byte. Sin embargo, siento que esto podría ser golfable.
dzaima
2
Formato de salida de matriz "fancy af" : ¡ Pruébelo en línea!
Adám
7

J , 12 bytes

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

Indexado a cero.

Pruébalo en línea!

Si puede eliminar todo el trabajo que estoy haciendo con las cajas, probablemente pueda reducir bastante el bytecount. Voy a ver si puedo resolver eso.

Explicación

Probablemente sea demasiado pronto para explicarlo (debería haber más campos de golf).

~. ,&.> <@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
col
fuente
2
Ese formato de salida de matriz es af de fantasía
Pavel
@Pavel también está tomando muchos bytes Π.Π
cole
5

05AB1E , 10 bytes

ÙεDIQƶ0K)˜

Pruébalo en línea!

Explicación

Ù             # 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
Emigna
fuente
5

Pitón 3 , 83 82 bytes

-1 byte gracias a Mego

lambda x:[[n]+[j for j,m in enumerate(x)if m==n]for n in sorted({*x},key=x.index)]

Pruébalo en línea!

Barra
fuente
1
j+1-> j(los índices pueden estar indexados a cero)
Mego
5

Adjunto , 15 bytes

Flat=>Positions

Pruébalo en línea!

Este es un caso interesante de =>la forma del operador de Map. Cuando se administra dos argumentos funcionales fy g, Mapdevuelve una función f => g[x]más x. Es decir, el RHS se aplica a la entrada, luego se asigna el LHS.

El builtin Positionsgenera una matriz que representa la agrupación de entradas por índices. Por defecto, cuando no se le proporciona un segundo argumento, Positionsutilizará el primer argumento. Flatluego se asigna sobre cada elemento, ya que eso es lo que requiere la pregunta.

Soluciones alternativas

31 bytes

MapArgs[Concat#~Indices,Unique]

Pruébalo en línea!

Una alternativa bastante corta, sin construcción. MapArgses una función como Map, excepto que puede alimentar argumentos adicionales en ella. Por ejemplo, MapArgs[{_1 + _2}, 1..3, 3]es [4, 5, 6]. Al igual Map, se convierte en curry cuando se le proporcionan dos argumentos funcionales. La función que se mapeará es Concat#~Indices, que es una bifurcación. Esta bifurcación se aplica a los Uniqueelementos de la entrada y a la entrada misma. Esto se traduce en Concat[_, Indices[_2, _]](con los argumentos de Indicesswapped through ~), que empareja el elemento que se está mapeando ( _) con los índices de dicho elemento _en la matriz de entrada, que es _2(como ffed throughMapArgs ).

43 bytes

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

Pruébalo en línea!

Esta es realmente una combinación más detallada (aunque un poco más legible) de las soluciones n. ° 1 y n. ° 2.

Conor O'Brien
fuente
4

Jalea , 6 bytes

Q;"ĠṢ$

Pruébalo en línea!

Explicación:

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
Erik el Outgolfer
fuente
No funciona para el último caso de prueba . La matriz debe estar anidada en otra capa, la salida siempre es bidimensional.
Pavel
@Pavel sí lo hace , me olvidé de agregar un pie de página (la respuesta es una función)
Erik the Outgolfer
Ok entonces, genial. Explicación pronto, ¿sí? : P
Pavel el
@Pavel agregó explicación
Erik the Outgolfer
4

Pyth , 7 bytes

0 indexado.

{+VQxRQ

Pruébalo aquí! Alternativa.

¿Cómo?

{+ VQxRQ - Programa completo.

     RQ - Para cada elemento ...
    x - Obtenga todos sus índices.
 + V - Y aplica la concatenación vectorizada.
   Q - Con la entrada.
{- Deduplicar.
Sr. Xcoder
fuente
4

MATL , 8 bytes

u"@tG=fh

Pruébalo en MATL Online

Explicación

        # 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
Suever
fuente
ooooohhh eso es inteligente! Tenía como 18 bytes tratando de usar, &fpero nunca lo hice funcionar.
Giuseppe
3

En realidad , 24 bytes

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

Pruébalo en línea!

Explicación:

;;╗⌠╝╜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
Mego
fuente
3

R , 56 bytes

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

Pruébalo en línea!


Este es mi primer intento de codegolf, por lo que cualquier comentario es bienvenido.

Florian
fuente
3
Bienvenido a PPCG! Buena primera respuesta.
Pavel el
1
Hola Florian! Muy buena respuesta. Esto es en realidad un fragmento en lugar de un programa o función, supone que la entrada está codificada x, pero tiene que haber una forma de leer la entrada, generalmente usamos scano definimos una función. Además, tiene que salir, por lo que tendría que envolver esto en a printo a cat.
Giuseppe
1
vea esta pregunta para más trucos de golf R prácticos :)
Giuseppe
1
¡Gracias chicos! ¡Y el enlace a los consejos r es ciertamente útil!
Florian
2
@Florian R no es tan malo como crees (excepto en desafíos de cuerdas ...) ¡siempre y cuando recuerdes que estás jugando golf contra otros golfistas R! No dudes en enviarme un ping en el chat si tienes preguntas. ¡Hay un par de golfistas de R que están activos, y definitivamente ofrecerán sugerencias y apreciarán las suyas también! Bienvenido al golf :)
Giuseppe
3

Wolfram Language (Mathematica) , 40 bytes

Salvó un byte gracias a Martin Ender.

KeyValueMap[{#,##&@@#2}&]@*PositionIndex

Pruébalo en línea!

alephalpha
fuente
Como @*PositionIndexfunciona
Pavel
@Pavel @*es composición de funciones. PositionIndexbásicamente hace todo el trabajo, pero devuelve una asociación en lugar de una lista.
alephalpha
1
{#,##&@@#2}&Guarda un byte.
Martin Ender
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])

Tenga en cuenta que esto supone que los números de entrada son positivos, entonces v> 0

Prueba ligeramente modificada (1 indexada) para que coincida con los casos de prueba

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))
})

edc65
fuente
3

NARS APL, 24 bytes, 12 caracteres

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

-4 bytes gracias a la prueba 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
└∊───────────┘
RosLuP
fuente
Afeitarse 4 bytes / 2 caracteres:{∪⍵,¨⍸¨⍵=⊂⍵}
Adám
3

SWI-Prolog , 165117 bytes

-48 bytes gracias a los consejos de golf 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)).

Pruébalo en línea!

Explicación

% 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)
    ).
mercator
fuente
3

K (oK) , 10 bytes

Solución:

(!x),'.x:=

Pruébalo en línea!

Ejemplos:

(!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)

Explicación:

La evaluación se realiza de derecha a izquierda. Todavía creo que esto es más apto para el golf ...

(!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 sin declarar x, (,/)'+(!;.)@'=abandonó este enfoque ...
callejero
fuente
1
Puede devolver el resultado indexado 0, por lo que creo que puede omitir el 1+.
Adám
2

Julia 0.6 , 37 bytes

Gracias a Pavel por 1 byte de descuento.

y->[[x;findin(y,[x])]for x=unique(y)]

Pruébalo en línea!

gggg
fuente
Elimine el espacio entre ]y forpara -1 byte.
Pavel
2

JavaScript (ES6), 68 bytes

0 indexado.

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

Casos de prueba

Arnauld
fuente
Los números de entrada son! = 0, eso podría ser útil para evitar el truco 1 / x
edc65
2

PHP 4.1, 88 bytes

Si, es bastante largo.

Esto supone un valor predeterminado php.ini archivo ( short_open_tag = Ony register_globals = On).

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

Esto presenta la matriz de una manera legible para los humanos.
Los valores se pueden pasar por POST, GET y COOKIE, dentro de la clave "A".


Para una versión moderna, uno puede usar (90 bytes):

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

El resultado es el mismo, excepto que todos los valores deben pasarse sobre los parámetros GET dentro de la clave "A".

Ismael Miguel
fuente
2

Perl 6 ,  63  61 bytes

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

Pruébelo (basado en 0)

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

Pruébalo (mismo algoritmo basado en 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])
Brad Gilbert b2gills
fuente
2

Japt , 14 9 bytes

0 indexado.

â £ð¶X iX

Intentalo

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

PHP 7.4+ , 71 bytes

* 73 bytes para citar la $_GETclave y evitar advertencias.

Fragmento: ( Demo )

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

Según el representante, supongo que IsmaelMiguel conoce la mejor manera de publicar código php en esta comunidad, así que estoy construyendo desde su fundación . No me queda claro si <?se debe incluir / contar en mi fragmento . Como esta es mi primera publicación, me alegra que alguien me explique si hay una sintaxis innecesaria. ps También leí Consejos para jugar al golf en PHP, que me parece un excelente candidato para la migración a Meta .

Las mejoras realizadas al fragmento de Ismael son:

  1. Asignación incondicional del primer elemento en cada submatriz (sobrescritura de valor)
  2. Splatpacking en lugar dearray_values() reindexar la salida.
mickmackusa
fuente
1

Kotlin , 83 bytes

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

Embellecido

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

Prueba

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

jrtapsell
fuente
Esta solución es un fragmento, no una función o programa completo. Requiere que la variable iesté predefinida. Puede hacer esto válido convirtiéndolo en una lambda que tome un parámetro i.
Pavel
Reelaborado para resolver el problema planteado por @Pavel
jrtapsell
1

Swift 4, 107 bytes

... Dios mío.

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

Sin golf:

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
        }
}

Es una pena que el diccionario pierda el orden, lo que me obliga a desperdiciar tantos caracteres en la clasificación de nuevo. Este tipo de abuso de los argumentos de cierre implícitos ( $0, $1, ...) y los miembros de tupla implícitos ( .0, .1, ...) es uhhhhh no es bonito.

Alexander - Restablece a Monica
fuente
1

Ruby , 54 52 bytes

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

Esta versión permite nil (53 bytes):

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

Pruébalo en línea!

Asone Tuhid
fuente
El desafío especifica que la matriz solo contendrá enteros positivos y habrá al menos un elemento. nilNo es un entero positivo.
Pavel
@Pavel gracias, lo comprobé pero lo perdí de alguna manera
Asone Tuhid