Уніфікація ідентифікаторів


31

Вступ

За визначенням, унікальні ідентифікатори повинні бути унікальними. Наявність декількох однакових ідентифікаторів призводить до отримання несподіваних даних. Але за даними, що надходять одночасно з декількох джерел, може бути важко забезпечити унікальність. Введіть функцію, яка уніфікує список ідентифікаторів.

Це, можливо, найгірший пазл, який я написав, але ви розумієте.

Вимоги

Давши список нульових чи більше додатних цілих чисел, застосуйте такі правила до кожного числа від першого до останнього:

  • Якщо число є першим у своєму роді, зберігайте його.
  • Якщо раніше зустрічалося число, замініть його найнижчим позитивним цілим числом, яке не зустрічається ніде у всьому списку вводу або будь-якому наявному виході.

Для рішення:

  • Рішенням може бути програма або функція.
  • Вхід може представляти собою рядок, масив, переданий як аргументи, або введення з клавіатури.
  • Виходом може бути рядок, масив або надрукований на екран.
  • Усі номери у списку вихідних даних є різними.

Припущення

  • Список вводу чистий. Він містить лише додатні цілі числа.
  • Позитивне ціле число має діапазон від 1 до 2 31 -1.
  • Для змінних вашої програми доступно менше 256 Мб пам'яті. (В основному не дозволяється використовувати массиви 2147 483 648 елементів.)

Випробування

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

Оцінка балів

Просто простий гольф з кодом. Найнижча кількість байтів до цього часу виграє наступного тижня.


4
Додати тестовий випадок: 6, 6, 1, 2, 3, 4, 56, 7, 1, 2, 3, 4, 5
Адама

2
@ Adám не повинен 6, 6, ...давати 6, 1, ...?
xnor

5
@ Adám Я думаю, ви маєте рацію з цього приводу, але формулювання може бути зрозумілішим, чи "set" посилається на елементи, що зустрічаються, на всі елементи вхідного списку або елементи в списку, як він є зараз?
xnor

3
@xnor 6, 6, 4, 4, 2, 2Тестовий випадок підтверджує тлумачення Адама: очікуваний вихід є 6, 1, 4, 3, 2, 5, а ні 6, 1, 4, 2, 3, 5.
Фаталізувати

2
Чи вважається 0 додатним цілим числом для цього виклику?
Лука

Відповіді:



8

Java 8, 158 144 байт

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++)щоб .contains(++m+c);)зберегти 1 байт і одночасно перетворити на Java 8, щоб зберегти ще 13 байт.

Пояснення:

Спробуйте тут.

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

Рубін , 63 байти

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

Спробуйте в Інтернеті!

Пояснення

->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 байт

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

Спробуйте в Інтернеті!

Пояснення

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

Я, мабуть, повинен використовувати зменшення замість карти ... Дозвольте мені побачити, чи це допомагає
Leaky Nun

@LeakyNun: Зниження чи карта - це часто шлях :)
Emigna


3
Дає [6, '1', '2', '3', '4', '5', '7']. Слід давати [6, '7', '1', '2', '3', '4', '5'].
Адам

1
@ Adám: Дякую за улов! Виправлено зараз :)
Емінья

6

PHP, 121 байт

<?$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);

Інтернет-версія

Розширено

$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 байт

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

Бере введення на клавіатурі, наприклад [3, 3, 3, 3, 3, 3].

Просто слідкуйте за найменшим додатним цілим числом, що jне використовується досі. Для кожного елемента xвводу виведіть, xякщо він xще не використаний, в іншому випадку виведіть j. Нарешті, оновітьj щоразу, коли щось виводить.

ВЕДЕНО: виправити помилку обробки даних [6, 6, 4, 4, 2, 2]. Дякуємо @Rod за вказівку на помилку та виправлення. Помилка полягала в тому, що у випадку повторюваного запису він видасть найменше число невикористаних до цієї точки списку, навіть якщо цей висновок з’явиться пізніше у введенні. (Це було неправильно, як було пояснено у публікації та коментарях, але я все-таки це заплутав.) У будь-якому випадку, виправлення полягало в тому, щоб просто додати список вводу aдо набору значень, які в цьому випадку неможливо вивести.


не працює [6,6,4,4,2,2], ви можете (можливо) виправити це, додавши +aдоwhile j in u: ->while j in u+a:
Род

@Rod Ти маєш рацію, моя помилка. (Я якось все-таки зіпсував це, незважаючи на коментарі з цього приводу - спасибі за те, що я звернув це на мою увагу - і я також не перевірив своє рішення досить добре проти тестових випадків. Збентежуючи.) Добре, я включив ваш дуже приємний виправити та перевірити його на основі тестових випадків. Спасибі!
mathmandan

5

Haskell , 79 76 байт

Редагувати:

  • -3 байти: @nimi бачив, що headможна замінити відповідність шаблону.

([]#)це анонімна функція отримання та повернення списку. Використовуйте як ([]#)[2147483647, 2, 2147483647, 2].

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

Спробуйте в Інтернеті!

Як це працює

  • ? є скороченим оператором для перевірки відсутності елемента у списку.
  • s#lобробляє список цілих чисел l, надаючи список sцілих чисел, які вже використовуються.
    • xце наступне ціле число, яке слід переглянути, yрешта.
    • z- це ціле число, вибране для наступного місця. Це xякщо xне є елементом s, а перше додатне ціле число ні в, sні в yіншому.
    • (z:s)#yпотім повторюється з zдоданим до списку використаних цілих чисел.
    • n є порожнім списком, оскільки непорожні списки оброблялися в попередньому рядку.
  • Основна функція ([]#)приймає список і викликає #з ним як другий аргумент, а порожній список для першого аргументу.

|z:_<-[x|...]...
німі

4

APL (Dyalog 16.0), 34 байти

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

2
Має бути кращий спосіб.
Адам


3

C # , 135 байт


Гольф

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

Безумовно

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

Незрозумілий читабельний

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

Повний код

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

Релізи

  • v1.0 - 135 bytes- Початкове рішення.

Примітки

  • Немає


3

R , 39 46 байт

Створює вектор із вхідного даних, а потім замінює дублювані значення діапазоном від 1 до мільйона, який видаляє вхідні значення. Повертає числовий вектор. Жоден вхід не поверне числовий порожній вектор (0).

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

Спробуйте в Інтернеті!

Це призведе до попередження про довжину вектора заміни

                           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 байт 133 байт

input = масив a, вихід = модифікований масив 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;}}

відформатовано

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

Забагато байтів витрачено на ці петлі. Хтось думає скоротити код, винайшов новий алгоритм (для якого використовується менше циклу)? Я думав, але не знайшов.


2

C # 7, 116 байт

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

Відступ

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

Пояснив

  • Перше виникнення числа завжди залишається таким, як є
  • послідовне виникнення числа виводиться із [1, 2, 3, ...]пропускання значень, що присутні у вводі.

Інтернет-версія


2

Clojure, 72 байти

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

Основне зменшення. Якщо iвін міститься в списку вихідних даних поки що, ми візьмемо 2-й елемент (1, коли 0-індексований) з нескінченного списку цілих чисел, (range)з яких ми видалили ті числа, які вже були використані. Діапазон починається з нуля, тому ми можемо брати не перший елемент, а другий.


1

R, 74 байти

читає список із stdin; повертає NULL для порожнього вводу.

o=c();for(i in n<-scan())o=c(o,`if`(i%in%o,setdiff(1:length(n),o)[1],i));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) може бути використаний, оскільки ми гарантуємо, що ніколи не буде потрібна заміна поза межами цього діапазону.

Спробуйте в Інтернеті!


0

Аксіома, 169 байт

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 і результат

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.