Uniquify Identifiers


31

Introdução

Por definição, identificadores únicos devem ser únicos. Ter vários identificadores iguais faz com que se recupere dados inesperados. Porém, com dados chegando simultaneamente de várias fontes, pode ser difícil garantir exclusividade. Escreva uma função que unifique uma lista de identificadores.

Este é possivelmente o pior quebra-cabeça que já escrevi, mas você entendeu.

Exigências

Dada uma lista de zero ou mais números inteiros positivos, aplique as seguintes regras a cada número, do primeiro ao último:

  • Se o número for o primeiro desse tipo, mantenha-o.
  • Se o número foi encontrado anteriormente, substitua-o pelo número inteiro positivo mais baixo que não foi encontrado em nenhum lugar da lista de entrada inteira ou em nenhuma saída existente.

Para a solução:

  • A solução pode ser um programa ou uma função.
  • A entrada pode ser uma sequência, uma matriz, passada como argumentos ou uma entrada do teclado.
  • A saída pode ser uma sequência, uma matriz ou impressa na tela.
  • Todos os números na lista de saída são distintos.

Suposições

  • A lista de entrada está limpa. Ele contém apenas números inteiros positivos.
  • Um número inteiro positivo tem o intervalo de 1 a 2 31 -1.
  • Menos de 256 MB de memória está disponível para as variáveis ​​do seu programa. (Basicamente, não são permitidas matrizes de 2.147.483.648 elementos.)

Casos de teste

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

Pontuação

Apenas um simples código de golfe. A contagem de bytes mais baixa nesse período na próxima semana vence.


4
Adicionar caso de teste: 6, 6, 1, 2, 3, 4, 56, 7, 1, 2, 3, 4, 5
Adám 3/17/17

2
@ Adám Não deveria 6, 6, ...dar 6, 1, ...?
xnor

5
@ Adám Acho que você está certo sobre isso, mas o texto pode ser mais claro: "set" se refere aos elementos encontrados, todos os elementos da lista de entrada ou elementos da lista como ela está agora?
Xnor

3
@xnor O 6, 6, 4, 4, 2, 2caso de teste confirma a interpretação de Adám: a saída esperada é 6, 1, 4, 3, 2, 5e não 6, 1, 4, 2, 3, 5.
Fatalize

2
0 conta como um número inteiro positivo para este desafio?
Lucas

Respostas:


11

Braquilog , 8 bytes

{|∧ℕ₁}ᵐ≠

Experimente online!

Explicação

{    }ᵐ     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, 158 144 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);)economizar 1 byte e simultaneamente convertido em Java 8 para economizar mais 13 bytes.

Explicações:

Experimente aqui.

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}

Experimente online!

Explicação

->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¬}ˆ}¯

Experimente online!

Explicação

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

Eu provavelmente deveria usar reduzir em vez de mapa ... deixe-me ver se isso ajuda
Leaky Nun

@LeakyNun: Reduzir ou mapa são muitas vezes o caminho a percorrer :)
Emigna


3
[6, '1', '2', '3', '4', '5', '7']. Deveria dar [6, '7', '1', '2', '3', '4', '5'].
Adám 3/17/17

1
@ Adám: Obrigado pela captura! Corrigido agora :)
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);

Versão Online

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

Recebe entrada do teclado, como [3, 3, 3, 3, 3, 3].

Basta acompanhar o menor número inteiro positivo jnão usado até o momento. Para cada elemento xda entrada, imprima xse xainda não tiver sido utilizado, caso contrário, imprima j. Finalmente, atualize jcada vez que você produz algo.

EDITADO: para corrigir um erro ao manipular a entrada de [6, 6, 4, 4, 2, 2]. Agradecemos a @Rod por apontar o erro e também uma correção. O erro foi que, no caso de uma entrada duplicada, ele produziria o menor número não utilizado para esse ponto da lista, mesmo que essa saída aparecesse posteriormente na entrada. (Isso estava errado, conforme esclarecido no post e nos comentários, mas ainda assim eu errei de alguma forma.) De qualquer forma, a correção era simplesmente adicionar a lista de entrada aao conjunto de valores que não poderiam ser exibidos nesse caso.


não funciona [6,6,4,4,2,2], você pode (provavelmente) consertá-lo adicionando +aao while j in u:->while j in u+a:
Rod

@ Rod Você está certo, meu erro. (De alguma forma, eu ainda errei tudo, apesar dos comentários sobre isso - obrigado por chamar minha atenção - e também não testei minha solução suficientemente bem contra os casos de teste. Embaraçoso.) OK, eu incorporei seu muito bom corrigir e verificá-lo nos casos de teste. Obrigado!
Mathmandan

5

Haskell , 79 76 bytes

EDITAR:

  • -3 bytes: @nimi viu que headpoderia ser substituído por uma correspondência de padrão.

([]#)é uma função anônima que recebe e retorna uma lista. Use como ([]#)[2147483647, 2, 2147483647, 2].

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

Experimente online!

Como funciona

  • ? é um operador abreviado para verificar se um elemento está ausente de uma lista.
  • s#llida com a lista de números inteiros l, dada uma lista sde números inteiros já usados.
    • xé o próximo número inteiro a ser observado, yos demais.
    • zé o número inteiro escolhido para o próximo ponto. É xif xnão é um elemento de s, e o primeiro número inteiro positivo nem em, snem em ycontrário.
    • (z:s)#yem seguida, recursa com zadicionado à lista inteira usada.
    • n é uma lista vazia, pois as listas não vazias foram tratadas na linha anterior.
  • A função principal ([]#)pega uma lista e a chama #como segundo argumento, e uma lista vazia para o primeiro argumento.

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

4

APL (Dyalog 16.0), 34 bytes

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

2
Deve haver uma maneira melhor.
Adám


3

C # , 135 bytes


Golfe

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

Ungolfed

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

Ungolfed legible

// 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();
      }
   }
}

Lançamentos

  • v1.0 - 135 bytes- Solução inicial.

Notas

  • Nenhum


3

R , 39 46 bytes

Cria um vetor da entrada e substitui os valores duplicados por um intervalo de 1 a um milhão que remove os valores de entrada. Retorna um vetor numérico. Nenhuma entrada retornará o vetor numérico vazio (0).

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

Experimente online!

Isso emitirá um aviso sobre o comprimento do vetor de substituição

                           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, saída = 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;}}

formatado

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

Muitos bytes desperdiçados para esses loop. Alguém pensa em encurtar o código inventando um novo algoritmo (que usa menos loop)? Eu estava pensando, mas ainda não encontrei um.


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

Recuado

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

  • a primeira ocorrência de um número é sempre deixada como está
  • são obtidas ocorrências consecutivas de um número [1, 2, 3, ...], ignorando os valores presentes na entrada.

Versão Online


2

Clojure, 72 bytes

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

Uma redução básica. Se iestiver contido na lista de saída até agora, pegaremos o segundo elemento (1 quando indexado com 0) da lista infinita de números inteiros (range)da qual removemos os números que já foram usados. O intervalo começa do zero, portanto não podemos pegar o primeiro elemento, mas o segundo.


1

R, 74 bytes

lê a lista de stdin; retorna NULL para uma entrada vazia.

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

explicação:

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) pode ser usado, pois garantimos que nunca precisamos de uma substituição fora desse intervalo.

Experimente online!


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 e 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
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.