Identificadores Uniquify


31

Introducción

Por definición, los identificadores únicos deberían ser únicos. Tener múltiples identificadores que son iguales hace que uno recupere datos inesperados. Pero con los datos que llegan simultáneamente de múltiples fuentes, puede ser difícil garantizar la unicidad. Escriba una función que uniquifique una lista de identificadores.

Esta es posiblemente la peor pelusa de rompecabezas que he escrito, pero entiendes la idea.

Requisitos

Dada una lista de cero o más enteros positivos, aplique las siguientes reglas a cada número de principio a fin:

  • Si el número es el primero de su tipo, consérvelo.
  • Si el número se ha encontrado previamente, reemplácelo con el entero positivo más bajo que no se encuentre en ninguna parte de la lista de entrada completa o en cualquier salida existente.

Para la solucion:

  • La solución puede ser un programa o una función.
  • La entrada puede ser una cadena, una matriz, pasada como argumentos o entrada de teclado.
  • La salida puede ser una cadena, una matriz o imprimirse en la pantalla.
  • Todos los números en la lista de salida son distintos.

Supuestos

  • La lista de entrada está limpia. Solo contiene enteros positivos.
  • Un entero positivo tiene el rango de 1 a 2 31 -1.
  • Hay menos de 256 MB de memoria disponibles para las variables de su programa. (Básicamente, no se permiten matrices de 2,147,483,648 elementos).

Casos de prueba

Input:  empty
Output: empty

Input:  5
Output: 5

Input:  1, 4, 2, 5, 3, 6
Output: 1, 4, 2, 5, 3, 6

Input:  3, 3, 3, 3, 3, 3
Output: 3, 1, 2, 4, 5, 6

Input:  6, 6, 4, 4, 2, 2
Output: 6, 1, 4, 3, 2, 5

Input:  2147483647, 2, 2147483647, 2
Output: 2147483647, 2, 1, 3

Tanteo

Solo un simple código de golf. El conteo de bytes más bajo para esta fecha la próxima semana gana.


44
Añadir caso de prueba: 6, 6, 1, 2, 3, 4, 56, 7, 1, 2, 3, 4, 5
Adám

2
@ Adám no debería 6, 6, ...dar 6, 1, ...?
xnor

55
@ Adám Creo que tienes razón al respecto, pero la redacción podría ser más clara. ¿"Set" se refiere a los elementos encontrados, a todos los elementos de la lista de entrada o a los elementos de la lista tal como están ahora?
xnor

3
@xnor El 6, 6, 4, 4, 2, 2caso de prueba confirma la interpretación de Adám: el resultado esperado es 6, 1, 4, 3, 2, 5, y no 6, 1, 4, 2, 3, 5.
Fatalize

2
¿Cuenta 0 como un entero positivo para este desafío?
Lucas

Respuestas:


11

Brachylog , 8 bytes

{|∧ℕ₁}ᵐ≠

Pruébalo en línea!

Explicación

{    }ᵐ     Map on the Input:
              Input = Output…
 |            …or…
  ∧ℕ₁         …Output is in [1,+inf)
       ≠    All elements of the output must be different
            (Implicit labeling)

8

Java 8, 158144 bytes

a->{int m=0;String r="",c=",",b=r;for(int x:a)b+=x+c;for(int x:a)if(r.contains(x+c)){for(;(r+b).contains(++m+c););r+=m+c;}else r+=x+c;return r;}
  • .contains(m+c);m++)para .contains(++m+c);)guardar 1 byte, y simultáneamente convertido a Java 8 para guardar 13 bytes más.

Explicaciones:

Pruébalo aquí.

a->{                      // Method with integer-array parameter and String return-type
  int m=0;                //  Lowest integer
  String r="",            //  Result-String
         c=",",           //  Comma delimiter for result String
         b=r;for(int x:a)b+=x+c;
                          //  Input array as String
  for(int x:a)            //  Loop (2) over the integers in the array
    if(r.contains(x+c)){  //   If the result already contains this integer
      for(;(r+b).contains(++m+c););
                          //    Inner (3) as long as either the result-String or array-String contains the lowest integer
                          //     and raise the lowest integer before every iteration by 1
      r+=m+c;             //    Append the result with this lowest not-present integer
    }else                 //   Else:
      r+=x+c;             //    Append the result-String with the current integer
                          //  End of loop (2) (implicit / single-line body)
  return r;               //  Return the result-String
}                         // End of method

7

JavaScript (ES6), 49 bytes

a=>a.map(g=(e,i)=>a.indexOf(e)-i?g(++n,-1):e,n=0)

7

Ruby , 63 bytes

->a{r=*0..a.size;r.map{|i|[a[i]]-a[0,i]==[]?a[i]=(r-a)[1]:0};a}

Pruébalo en línea!

Explicación

->a{                                    # Anonymous function with one argument
    r=*0..a.size;                       # Numbers from 0 to array size
    r.map{|i|                           # For all numbers in range:
        [a[i]]                          #  Get array with just a[i]
              -a[0,i]                   #  Remove elements from array that are
                                        #    also in a[0..i-1]
                    ==[]?               #  Check if result is an empty array
                        a[i]=           #  If true, set a[i] to:
                             (r-a)      #   Remove elements from number range
                                        #     that are also in input array
                                  [1]   #   Get second element (first non-zero)
                        :0};            #  If false, no-op
                            a}          # Return modified array

6

05AB1E , 17 16 18 bytes

vy¯yåi¹gL¯K¹K¬}ˆ}¯

Pruébalo en línea!

Explicación

v                    # for each y in input
 y                   # push y
  ¯yåi               # if y exist in global list
      ¹gL            # push [1 ... len(input)]
         ¯K          # remove any number that is already in global list
           ¹K        # remove any number that is in the input
             ¬       # get the first (smallest)
              }      # end if
               ˆ     # add to global list
                }¯   # end loop, push and output global list

Probablemente debería usar reducir en lugar de mapa ... déjame ver si eso ayuda
Leaky Nun

@LeakyNun: Reducir o asignar son a menudo el camino a seguir :)
Emigna


3
Da [6, '1', '2', '3', '4', '5', '7']. Debería dar [6, '7', '1', '2', '3', '4', '5'].
Adám

1
@ Adám: ¡Gracias por la captura! Reparado ahora :)
Emigna

6

PHP, 121 bytes

<?$n=array_diff(range(0,count($g=$_GET)),$g);sort($n);$r=[];foreach($g as$v)$r[]=in_array($v,$r)?$n[++$i]:$v;print_r($r);

Versión en línea

Expandido

$n=array_diff(range(0,count($g=$_GET)),$g); # create array of ascending values which are not in input array plus zero
sort($n); # minimize keys
$r=[];  # empty result array
foreach($g as$v) # loop input array
  $r[]=in_array($v,$r)?$n[++$i]:$v; # if value is not in result array add value else take new unique value skip zero through ++$i
print_r($r); # output result array

5

Python 2, 77 79 bytes

a=input();u=[];j=1
for x in a:
 u+=[[x,j][x in u]]
 while j in u+a:j+=1
print u

Toma entrada de teclado, como [3, 3, 3, 3, 3, 3].

Simplemente realice un seguimiento del entero positivo más pequeño que jno se haya utilizado hasta ahora. Para cada elemento xde la entrada, salida xsi xaún no se ha utilizado, de lo contrario salida j. Finalmente, actualice jcada vez que envíe algo.

EDITADO: para corregir un error al manejar la entrada de [6, 6, 4, 4, 2, 2]. Gracias a @Rod por señalar el error y una solución. El error fue que, en el caso de una entrada duplicada, generaría el número más pequeño sin usar hasta ese punto de la lista, incluso si esa salida apareciera más tarde en la entrada. (Esto estaba mal, como se aclaró en la publicación y los comentarios, pero aún así lo estropeé de alguna manera.) De todos modos, la solución fue simplemente agregar la lista de entrada a, al conjunto de valores que no se podrían generar en ese caso.


no funciona [6,6,4,4,2,2], puede (probablemente) solucionarlo agregando +aa while j in u:->while j in u+a:
Rod

@ Rod Tienes razón, mi error. (De alguna manera, aún lo estropeé a pesar de los comentarios al respecto, gracias por llamar mi atención, y tampoco probé mi solución lo suficientemente bien contra los casos de prueba. Vergonzoso). OK, he incorporado su muy agradable arreglarlo y verificarlo contra los casos de prueba. ¡Gracias!
Mathmandan

5

Haskell , 79 76 bytes

EDITAR:

  • -3 bytes: @nimi vio que headpodría ser reemplazado por una coincidencia de patrón.

([]#)es una función anónima que toma y devuelve una lista. Utilizar como ([]#)[2147483647, 2, 2147483647, 2].

(?)=notElem
s#(x:y)|z:_<-[x|x?s]++filter(?(s++y))[1..]=z:(z:s)#y
_#n=n
([]#)

Pruébalo en línea!

Cómo funciona

  • ? es un operador abreviado para verificar si un elemento está ausente de una lista.
  • s#lmaneja la lista de enteros l, dada una lista sde enteros ya utilizados.
    • xes el siguiente entero a mirar, ylos restantes.
    • zes el entero elegido para el próximo lugar. Es xsi xno es un elemento de s, y el primer entero positivo ni en sni de yotra manera.
    • (z:s)#yluego se repite con zagregado a la lista entera utilizada.
    • n es una lista vacía, ya que las listas no vacías se han manejado en la línea anterior.
  • La función principal ([]#)toma una lista y la llama #como segundo argumento, y una lista vacía para el primer argumento.

|z:_<-[x|...]...
nimi

4

APL (Dyalog 16.0), 34 bytes

(s↑v~⍨⍳⌈/v+s←+/b←(⍳≢v)≠⍳⍨v)@{b}v←⎕

2
Tiene que haber una mejor manera.
Adám


3

C # , 135 bytes


Golfed

(int[] i)=>{for(int x=1,v,m=0,l=i.Length,y;x<l;x++){v=i[x];for(y=0;y<l&&v==i[x]?y<x:y<l;y++)if(i[y]==v){v=++m;y=-1;}i[x]=v;}return i;};

Sin golf

( int[] i ) => {
   for( int x = 1, v, m = 0, l = i.Length, y; x < l; x++ ) {
      v = i[ x ];

      for( y = 0; y < l && v == i[ x ] ? y < x : y < l ; y++ )
         if( i[ y ] == v ) {
            v = ++m;
            y = -1;
         }

      i[ x ] = v;
   }

   return i;
};

Legible sin golf

// Takes an array of Int32 objects ( 32-byte signed integers )
( int[] i ) => {

   // Cycles through each element on the array
   //   x: Scan position, starts at the 2nd element
   //   v: Value being processed
   //   m: The next minimum value to replace
   //   l: Size of the array, to save some byte count
   for( int x = 1, v, m = 0, l = i.Length, y; x < l; x++ ) {

      // Hold the value
      v = i[ x ];

      // Re-scan the array for a duplicate value up the the current position ( 'x' ) IF
      //   ... the currently hold value hasn't been modified
      //   ... otherwise, re-scans the entire array to find a suitable value to replace
      for( y = 0; y < l && v == i[ x ] ? y < x : y < l ; y++ )

         // Check if 'v' shares the same value with other element
         if( i[ y ] == v ) {

            // Set 'v' to the minimum value possible
            v = ++m;

            // Reset the scan position to validate the new value
            y = -1;
         }

      // Set the 'v' to the array
      i[ x ] = v;
   }

   // Return the array
   return i;
};

Código completo

using System;
using System.Collections.Generic;

namespace Namespace {
   class Program {
      static void Main( String[] args ) {
         Func<Int32[], Int32[]> f = ( int[] i ) => {
            for( int x = 1, v, m = 0, l = i.Length, y; x < l; x++ ) {
               v = i[ x ];

               for( y = 0; y < l && v == i[ x ] ? y < x : y < l ; y++ )
                  if( i[ y ] == v ) {
                     v = ++m;
                     y = -1;
                  }

               i[ x ] = v;
            }

            return i;
         };

         List<Int32[]>
            testCases = new List<Int32[]>() {
               new Int32[] { },
               new Int32[] { 5 },
               new Int32[] { 1, 4, 2, 5, 3, 6 },
               new Int32[] { 3, 3, 3, 3, 3, 3 },
               new Int32[] { 6, 6, 4, 4, 2, 2 },
               new Int32[] { 2147483647, 2, 2147483647, 2 },
            };

         foreach( Int32[] testCase in testCases ) {
            Console.WriteLine( $" Input: {String.Join( ",", testCase )}\nOutput: {string.Join( ",", f( testCase ) )}\n" );
         }

         Console.ReadLine();
      }
   }
}

Lanzamientos

  • v1.0 - 135 bytes- Solución inicial.

Notas

  • Ninguna


3

R , 39 46 bytes

Crea un vector a partir de la entrada, luego reemplaza los valores duplicados con un rango de 1 a un millón que tiene los valores de entrada eliminados. Devuelve un vector numérico. Ninguna entrada devolverá el vector numérico vacío (0).

i[duplicated(i)]=(1:1e6)[-(i=scan())];i

Pruébalo en línea!

Esto arrojará una advertencia sobre la longitud del vector de reemplazo

                           i=scan()     # set i as input
                 (1:1e6)                # 1 to a million (could go higher)
                 (1:1e6)[-(i=scan())]   # without input values
  duplicated(i)                         # duplicate values in i
i[duplicated(i)]=(1:1e6)[-(i=scan())]   # set duplicate i values to reduced range vector
                                     ;i # return result

3

C, 169 bytes 133 bytes

entrada = matriz a, salida = matriz modificada a

i=1,j,k,l;void f(int*a,int n){for(;i<n;i++)for(j=i-1;j>=0;j--)if(a[i]==a[j]){l=1;for(k=0;k<n;)if(l==a[k])k=l++?0:0;else k++;a[i]=l;}}

formateado

int i, j, k, l;
void f(int* a, int n)
{
    for (i = 1; i<n; i++)
        for (j = i - 1; j >= 0; j--)
            if (a[i] == a[j])
            {
                l = 1;
                for (k = 0; k<n;)
                    if (l == a[k])
                        k = l++ ? 0 : 0;
                    else
                        k++;
                a[i] = l;
            }
}

Demasiados bytes desperdiciados para estos bucles. ¿Alguien piensa en acortar el código inventando un nuevo algoritmo (que usa menos bucle)? Estaba pensando pero no he encontrado uno.


2

C # 7, 116 bytes

int[]f(int[]c){int j=0;int h()=>c.Contains(++j)?h():j;return c.Select((e,i)=>Array.IndexOf(c,e)<i?h():e).ToArray();}

Sangrado

int[] f(int[] c)
{
    int j = 0;
    int h() => c.Contains(++j) ? h() : j;
    return c
        .Select((e, i) => Array.IndexOf(c, e) < i ? h() : e)
        .ToArray();
}

Explicado

  • la primera aparición de un número siempre se deja como está
  • Se obtienen ocurrencias consecutivas de un número [1, 2, 3, ...], omitiendo los valores presentes en la entrada.

Versión en línea


2

Clojure, 72 bytes

#(reduce(fn[r i](conj r(if((set r)i)(nth(remove(set r)(range))1)i)))[]%)

Una reducción básica. Si hasta ahora iestá contenido en la lista de salida, tomaremos el segundo elemento (1 cuando está indexado a 0) de la lista infinita de enteros (range)de los que hemos eliminado aquellos números que ya se han utilizado. El rango comienza desde cero, por lo que no podemos tomar el primer elemento sino el segundo.


1

R, 74 bytes

lee la lista de stdin; devuelve NULL para una entrada vacía.

o=c();for(i in n<-scan())o=c(o,`if`(i%in%o,setdiff(1:length(n),o)[1],i));o

explicación:

o=c()                                #initialize empty list of outputs
for(i in n<-scan())                  # loop through the list after reading it from stdin
    o=c(o,                           # set the output to be the concatenation of o and
      `if`(i%in%o,                   # if we've seen the element before
           setdiff(1:length(n),o)[1] # the first element not in 1,2,...
           ,i))                      # otherwise the element
o                                    # print the output

1:length(n) puede usarse ya que estamos garantizados de que nunca necesitaremos un reemplazo fuera de ese rango.

Pruébalo en línea!


0

Axioma, 169 bytes

f a==(r:List INT:=[];for i in 1..#a repeat(~member?(a.i,r)=>(r:=concat(r,a.i));for j in 1..repeat if~member?(j,r)and(~member?(j,a)or j=a.i)then(r:=concat(r,j);break));r)

ungolf y resultado

ff(a)==
  r:List INT:=[]
  for i in 1..#a repeat
      ~member?(a.i,r)=>(r:=concat(r,a.i))
      for j in 1.. repeat
            if~member?(j,r)and(~member?(j,a) or j=a.i)then(r:=concat(r,j);break)
  r

(3) -> f([])
   (3)  []
                                                       Type: List Integer
(4) -> f([5])
   (4)  [5]
                                                       Type: List Integer
(5) -> f([1,4,2,5,3,6])
   (5)  [1,4,2,5,3,6]
                                                       Type: List Integer
(6) -> f([3,3,3,3,3,3])
   (6)  [3,1,2,4,5,6]
                                                       Type: List Integer
(7) -> f([6, 6, 4, 4, 2, 2])
   (7)  [6,1,4,3,2,5]
                                                       Type: List Integer
(8) -> f([2147483647, 2, 2147483647, 2])
   (8)  [2147483647,2,1,3]
                                                       Type: List Integer
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.