Implementare le operazioni bag


20

Una borsa , chiamata anche multiset, è una collezione non ordinata. Puoi chiamarlo un set che consente duplicati o un elenco (o un array) che non è ordinato / indicizzato. In questa sfida, ti viene chiesto di implementare le operazioni di borsa: addizione, differenza, moltiplicazione, divisione, conteggio e test di uguaglianza.

operazioni

Le operazioni specificate potrebbero non essere convenzionali.

  • Inoltre combina due buste in una, conservando il numero totale di ciascun valore
    [1,2,2,3] + [1,2,4] = [1,1,2,2,2,3,4]
  • la differenza rimuove da un sacchetto ogni elemento di un altro sacchetto o non fa nulla se non è presente tale elemento
    [1,2,2,4] - [1,2] = [2,4] [1,2,3] - [2,4] = [1,3]
  • la moltiplicazione moltiplica ogni elemento nel sacchetto.
    [1,2,3,3,4] * 3 = [1,1,1,2,2,2,3,3,3,3,3,3,4,4,4] 2 * [1,3] = [1,1,3,3]
  • la divisione è insolita: ogni n elementi uguali vengono messi in n nuovi sacchetti uguali, gli elementi che non possono formare un gruppo n rimangono nel sacchetto. Restituisci una delle n nuove borse.
    [1,1,2,2,2] / 2 = [1,2] [1,2,2,3,3,3] / 3 = [3]
  • conteggio conta quanti sacchetti divisori possono essere prodotti dal sacchetto dividendi
    [1,1,2,2,2,2,3,3,3] c [1,2,3] = 2
  • test di uguaglianza verifica se due sacchi hanno gli stessi numeri di ciascun elemento
    [1,2,2,3] == [3,2,1,2] = truthy [1,2,3] == [1,2,2,3] = falsy(può essere utilizzato anche =per questo)

Se si utilizzano i propri simboli per gli operatori, si prega di specificare.

formati

I sacchetti verranno visualizzati come elenchi del modulo [1,1,2,3,4]. Puoi usare qualsiasi parentesi diversa da quelle quadrate, o anche usare virgolette o niente del tutto. Gli elementi saranno numeri interi (matematicamente, non necessariamente int) ai fini di questa domanda. I bagagli non devono essere ordinati.

Il formato di input sarà due sacchetti o un sacchetto e un numero intero, con un operatore. Puoi specificare il tuo formato purché contenga questi tre.

Il formato di output dovrebbe essere un singolo sacchetto dello stesso formato.

Regole

  • non è possibile utilizzare funzioni integrate, operazioni o librerie (inclusa la libreria standard) che già le implementano; va bene però usare la concatenazione e la moltiplicazione di elenchi poiché sono operazioni per elenco di definizioni, non operazioni di borsa (che in pratica fanno la stessa cosa)
  • si applicano scappatoie standard
  • vince la risposta più breve

Casi test

[1,2,2,3] + [1,2,4]
[1,1,2,2,2,3,4]

[1,2,2,4] - [1,2]
[2,4]

[1,2,3] - [2,4]
[1,3]

[1,2,3,3,4] * 3
[1,1,1,2,2,2,3,3,3,3,3,3,4,4,4]

2 * [1,3]
[1,1,3,3]

[1,1,2,2,2] / 2
[1,2]

[1,2,2,3,3,3] / 3
[3]

[1,1,2,2,2,2,3,3,3] c [1,2,3]
2

[3,2,1,2] == [1,2,2,3]
truthy

[1,2,3] == [1,2,2,3]
falsy

2
Forse rilassare il formato di input? Ad esempio, consenti di prendere la borsa, la borsa / il numero e l'operatore come argomenti separati o in un formato libero. Altrimenti una parte importante della sfida è l'analisi dell'input, che non è particolarmente interessante
Luis Mendo,

@LuisMendo split-on-space è sufficiente per analizzare questo, se hai un linguaggio in grado di valutare le stringhe come liste, non credi? Sono inesperto nel pubblicare sfide, quindi per favore illuminami :-)
busukxuan

Non sono riuscito a trovare un meta post rilevante, ma vedi ad esempio la formulazione qui : puoi leggere l'intero come sua rappresentazione decimale, rappresentazione unaria (usando un carattere a tua scelta), array di byte (grande o piccolo endiano) o byte singolo (se questo è il tipo di dati più grande per la tua lingua) . Oppure qui : i formati di input e output sono flessibili come al solito (array, elenchi, elenchi di elenchi, stringhe con separatori ragionevoli, ecc .).
Luis Mendo,

@LuisMendo è praticamente gratuito ora. E per quanto riguarda l'intero, intendevo solo che in senso matematico, non il tipo di dati.
busukxuan,

1
@LuisMendo no, i simboli devono avere un senso, anche se solo un po '. Bene, puoi usare one = per il test di uguaglianza.
busukxuan,

Risposte:


3

05AB1E, 92 87 83 82 77 byte

>i‚˜,}¹iи˜Qis}GD})˜,}¹<i³v²y¢O}){0è,}¹Íi{s{Q,}¹Í<iÙv²y¢O³‹_iy}}),}svy†¬yQi¦}}

Dividi per operazione

>i                      # if 0
  ‚˜,}                  # addition
¹i                      # if 1
  и˜Qis}GD})˜,}        # multiplication
¹<i                     # if 2
   ³v²y¢O}){0è,}        # count
¹Íi                     # if 3
   {s{Q,}               # equality
¹Í<i                    # if 4
   Ùv²y¢O³÷Fy}}),}      # division
                        # else
   svy†¬yQi¦}}          # difference

Spiegazione

aggiunta

‚˜,}

Metti un sacchetto nell'altro e appiattiscilo in un sacchetto.

Moltiplicazione

и˜Qis}

Assicurati che il numero sia in cima alla pila. Chiama questa X.

GD})˜,}

Duplica la borsa X volte e unisciti a una borsa.

Contare

³v²y¢O}){0è,}

Per ogni elemento nel sacchetto divisore, conta il numero di occorrenze nel sacchetto dividendi.
Il conteggio minimo sarà il numero di borse che possiamo fare.

Uguaglianza

 {s{Q,}

Ordina entrambi i sacchetti e controlla se sono uguali.

Divisione

Ùv²y¢O³÷Fy}}),}

Conta quante volte ogni singolo elemento si presenta nella borsa.
Se si verifica almeno quante volte il divisore. Conserva (nr_of_copies_total // divisor) copie nel sacchetto.

Differenza

svy†¬yQi¦}} 

Per ogni elemento nel subtrahend, ordinalo nella parte anteriore del minuend.
Se il subtrahend corrente è uguale al primo elemento nel minuend, rimuoverlo dal minuend.


9

APL (155)

∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕

Ciò definisce una "borsa" dell'operatore , che definisce le operazioni della borsa per determinate funzioni. Cioè +∆sarebbe aggiunta. Quindi legge una riga dalla tastiera e la valuta come espressione APL.

Le funzioni sono:

  • +∆, inoltre
  • -∆, sottrazione
  • ×∆, moltiplicazione
  • ÷∆, divisione
  • ⊂∆, contando
  • ≡∆, equivalenza (anche se a causa del golf qualsiasi funzione non riconosciuta farà equivalenza)

Spiegazione:

  • ∆←{... }: definire un operatore :

    • O←⍺⍺: memorizza la funzione specificata in O( ⎕CRnon funziona ⍺⍺direttamente con )
    • O←⎕CR'O': ottiene la rappresentazione in forma di stringa di quella funzione
    • '+'=O... :: per aggiunta,
      • ⍺,⍵: unire le due liste insieme
      • R[⍋R←... ]: e ordina il risultato
    • '-'=O:: per sottrazione,
      • ⍺{... }⍵: esegue la seguente funzione ricorsiva:
        • ⍵≡⍬:⍺: se il subtrahend è vuoto, restituisce il minuend
        • ⍺/⍨(⍳⍴⍺)≢⍺⍳⊃⍵∇1↓⍵: in caso contrario, rimuovere il primo elemento del subtrahend sia dal subtrahend che dal minuend e riprovare
    • (⍬=⍴⍵)∧K←'×'=O: per moltiplicazione, e se l'argomento giusto non è un sacchetto:
      • ⍵/⍺: replica ogni elemento nell'argomento sinistro dall'argomento destro
    • K:: ... e se l'argomento giusto è una borsa:
      • ⍺/⍵: replica ogni elemento nell'argomento destro con l'argomento sinistro (questo è così che la moltiplicazione è commutativa)
    • '÷'=O:: per divisione,
      • ⍵≤⍺∘.+⍺: vedi quali elementi in ⍺ si verificano almeno ⍵ volte,
      • ⍺/⍨: seleziona quelli da ⍺,
      • : e rimuove tutti i duplicati da quell'elenco
    • '⊂'=O:: per contare,
      • ⍵{... }⍺: esegue la seguente funzione ricorsiva:
        • (∪⍺)≢∪⍵:0: se un elenco contiene elementi che l'altro non ha, il risultato è 0
        • 1+⍺∇⍵-∆⍺: altrimenti, sottrarre il dividendo dal divisore, riprovare e incrementare il risultato.
    • : se nessuna delle precedenti, effettua il test di equivalenza:
      • ⍺[⍋⍺]≡⍵[⍋⍵]: ordina entrambi gli elenchi e verifica se sono uguali
  • : legge un'espressione dalla tastiera, la valuta e genera il risultato.

Casi test:

      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 2 3 +∆ 1 2 4
1 1 2 2 2 3 4
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 2 4 -∆ 1 2
2 4
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 3 -∆ 2 4
1 3
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 3 3 4 ×∆ 3
1 1 1 2 2 2 3 3 3 3 3 3 4 4 4
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      2 ×∆ 1 3
1 1 3 3
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 1 2 2 2 ÷∆ 2
1 2
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 2 3 3 3 ÷∆ 3
3
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 1 2 2 2 2 3 3 3 ⊂∆ 1 2 3
2
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      3 2 1 2 ≡∆ 1 2 2 3
1
      ∆←{O←⍺⍺⋄'+'=O←⎕CR'O':R[⍋R←⍺,⍵]⋄'-'=O:⍺{⍵≡⍬:⍺⋄(⍺/⍨(⍳⍴⍺)≠⍺⍳⊃⍵)∇1↓⍵}⍵⋄(⍬≡⍴⍵)∧K←'×'=O:⍵/⍺⋄K:⍺/⍵⋄'÷'=O:∪⍺⌿⍨⍵≤+/⍺∘.=⍺⋄'⊂'=O:⍵{(∪⍺)≢∪⍵:0⋄1+⍺∇⍵-∆⍺}⍺⋄⍺[⍋⍺]≡⍵[⍋⍵]}⋄⎕
⎕:
      1 2 3 ≡∆ 1 2 2 3
0

Soluzione davvero professionale e ottima scrittura! +1

Il tuo commento e la tua spiegazione sono davvero solidi! Una cosa, però: per divisione, credo che la specifica sia formulata in un modo che [2,2,2,2,2,2]/3dovrebbe dare [2,2], ma la tua sembra dare [2].
Value Ink

Non è necessario codificare il REPL. Se lo definisci , l'utente verrà scaricato nel REPL nativo di APL, dove è ora valido. Penso che puoi salvare alcuni byte spostando la sottrazione alla fine in quanto è l'unico che richiede due righe. Invece di ⎕CR, usa *per simboleggiare count, e do O←⍺⍺2, quindi 2=O:per plus, 1=Oper mult, 0=O:per equiv, 7<O:per count e 0<O:per div (con implicito 0>O:per subtr).
Adám,

6

JavaScript (ES6), 260 byte

(x,o,y,a=a=>a.reduce((r,e,i)=>[...r,...Array(e).fill(i)],[]),b=(a,r=[])=>a.map(e=>r[e]=-~r[e])&&r)=>[z=>a(b(y,z)),z=>y.map(e=>z[e]&&z[e]--)&&a(z),z=>a(z.map(e=>e*y)),z=>a(z.map(i=>i/y|0)),z=>b(y).map((e,i)=>r=Math.min(r,z[i]/e),r=1/0)|r,z=>``+z==b(y)][o](b(x))

Accetta 3 parametri. Il primo parametro è un array, il secondo è un operatore, il terzo dipende dall'operatore. I sacchetti sono tenuti a contenere numeri interi non negativi.

[...] 0 [...] -> addition
[...] 1 [...] -> difference
[...] 2 <n> -> multiplication
[...] 3 <n> -> division
[...] 4 [...] -> counting
[...] 5 [...] -> equality

Ungolfed:

function do_bag_op(lhs, op, rhs) {
    function bag2array(bag) {
        return bag.reduce(function (result, entry, index) {
            return result.concat(Array(entry).fill(index));
        }, []);
    }
    function array2bag(array, bag) {
        if (!bag) bag = [];
        array.forEach(function (entry) {
            if (bag[entry]) bag[entry]++;
            else bag[entry] = 1;
        }
        return bag;
    }
    var bag = array2bag(lhs);
    switch (o) {
    case 0: // addition
        return bag2array(array2bag(rhs, bag));
    case 1: // difference
        rhs.forEach(function(entry) {
            if (bag[entry]) bag[entry]--;
        });
        return bag2array(bag);
    case 2: // multiplication
        return bag2array(bag.map(function (entry) {
            return entry * rhs;
        }));
    case 3: // division
        return bag2array(bag.map(function (entry) {
            return Math.floor(entry / rhs);
        }));
    case 4: // counting
        return Math.floor(array2bag(rhs).reduce(function (count, entry, index) {
            return Math.min(count, bag[index] / entry);
        }, Infinity));
    case 5: // equality
        return String(bag) == String(array2bag(rhs));
    }
}

6

Ottava, 253 244 226 byte

function r=f(a,b,o)
u=union(a,b);p=hist(a,u);q=hist(b,u);m=d=0;if(numel(b)==1)m=p.*b;d=p/b;elseif(numel(a)==1)m=a.*q;end
r={p+q,p-q,m,d,min(fix(p./q)),isequal(p,q)}{o};if(o<5)r=[arrayfun(@(x,y)repmat(y,1,x),r,u,'un',0){:}];end

Questa funzione deve essere in un file. Per scrivere la funzione nella finestra di comando è necessario utilizzare endfunctiono end.

Grazie a Luis Mendo per aver salvato 18 byte.

Le operazioni sono:

1 = addition
2 = difference
3 = multiplication
4 = division
5 = counting
6 = equality test

Esempio di utilizzo:

>> f([1,2,2,3], [1,2,4], 1)
ans = 1   1   2   2   2   3   4

>> f([1,2,2,4], [1,2], 2)
ans = 2   4

>> f([1,2,3], [2,4], 2)
ans = 1   3

>> f([1,2,3,3,4], 3, 3)
ans = 1   1   1   2   2   2   3   3   3   3   3   3   4   4   4

>> f(2, [1,3], 3)
ans = 1   1   3   3

>> f([1,1,2,2,2], 2, 4)
ans = 1   2

>> f([1,2,2,3,3,3], 3, 4)
ans =  3

>> f([1,1,2,2,2,2,3,3,3], [1,2,3], 5)
ans =  2

>> f([3,2,1,2], [1,2,2,3], 6)
ans =  1

>> f([1,2,3], [1,2,2,3], 6)
ans = 0

Ungolfed:

function r = f(a,b,o)
    u = union(a,b);
    p = hist(a,u);
    q = hist(b,u);
    m = d = 0;
    if (numel(b)==1)
        m = p.*b;
        d = p/b;
    elseif (numel(a)==1) 
        m = a.*q;
    end
    r = {p+q, p-q, m, d, min(fix(p./q)), isequal(p,q)}{o};
    if (o<5)
        r = [arrayfun(@(x,y) repmat(y, 1, x), r, u, 'un', 0){:}];
    end
end

5

Matematica, 387 347 300 284 byte

k=KeyValueMap[Table,#]&;j=b@@Join@@#&;l=List;q=Counts
b~SetAttributes~Orderless
a_b+c_b^:=j@{a,c}
c_b-a_b^:=j@k@Merge[q/@(l@@@{a+c,2a}),-Min[0,+##2-#]&@@#&]
a_b*n_Integer/;n>0^:=a+a*(n-1)
a_Rational c_b^:=j@k[⌊a#⌋&/@q@*l@@c]
a_b==d_b^:=l@@a==l@@d
c_b/a_b^:=If[(c-a)+a==c,1+(c-a)/a,0]

Leggermente degradato (alias versione precedente), non aveva pieno supporto per i test di uguaglianza (restituiva valori di verità, ma non veniva valutato per borse non corrispondenti).

SetAttributes[b,Orderless]
b/:-a_b:=d@@a
b/:a_b+c_b:=Join[a,c]
d/:a_b+c_d:=b@@Join@@KeyValueMap[Table,Merge[Counts/@(List@@@{a+b@@c,b@@c+b@@c}),Max[0,#-(+##2)]&@@#&]]
b/:Rational[1,a_]c_b:=b@@Join@@KeyValueMap[Table,Floor[#/a]&/@Counts@*List@@c]
b/:(a_b)^-1:=c@@a
c/:a_b d_c:=Min@Merge[Counts/@(List@@@{a,d}),If[+##2==0,\[Infinity],#/+##2]&@@#&]
b/:a_b*n_Integer:=a+a*(n-1)

Implementa il tipo di dati richiesto con head b.

Il primo bè definito come Orderless. Qualsiasi oggetto passato al kernel con head bordinerà automaticamente i suoi argomenti. Quindi, anche se b[3,2,1]digitato, il valutatore non vedrà altro che b[1,2,3].

L'aggiunta è banalmente definita come unire gli elementi.

È definita una regola speciale per la differenza di due sacchi (spiegata di seguito). La versione precedente aveva un simbolo ausiliario per le espressioni della forma -bag.

Quindi la moltiplicazione (purché nsia un numero intero positivo) viene definita in modo ricorsivo n*b[...] = b[...] + (n-1)*b[...]che alla fine si ridurrà a una somma semplice.

La regola speciale per b[...] - b[...]conta il numero di elementi distinti nella somma dei sacchi e sottrae il sacco da sottrarre due volte da quel risultato. Più facile spiegato:

b[1,2,3,4,5] - b[2,3,6]
Element counts in sum of bags: <|1->1, 2->2, 3->2, 4->1, 5->1, 6->1|>
Element counts in 2x second bag:     <|2->2, 3->2, 6->2|>
Subtracting the corresponding values:
                               <|1->1, 2->0, 3->0, 4->1, 5->1, 6->-1|>

Sopra è un elenco di Keys->Values. KeyValueMapcon Tablecrea elenchi di ogni Key Valuevolta. (c'è anche un Max[...,0]lì per non tentare la creazione di tabelle di lunghezza negativa). Questo viene fuori come:

{{1},{},{},{4},{5},{}}

che viene appiattito e la testa Listviene sostituita con b.

La divisione per numeri interi è in qualche modo simile nelle funzioni utilizzate, è semplicemente la divisione di base dell'elemento conta per l'intero.

Divisione per set o conteggio Ho cambiato dall'implementazione originale. Ora è ricorsivamente fatto come segue. Diciamo, dividiamo la borsa b1per b2(che nel codice di golf sono ce arispettivamente. Se (b1-b2) + b2 == b1, quindi aggiungi 1 e aggiungi a quello il risultato della divisione (b1-b2)/b2. In caso contrario, restituisci 0 ed esci dalla ricorsione.

Se le borse si abbinano, il sistema integrato ==True. L'ultima riga forza un Falsese non lo fanno.

Casi test:

Input:
b[1, 2, 2, 3] + b[1, 2, 4]
b[1, 2, 2, 4] - b[1, 2]
b[1, 2, 3] - b[2, 4]
b[1, 2, 3, 3, 4]*3
2*b[1, 3]
b[1, 1, 2, 2, 2]/2
b[1, 2, 2, 3, 3, 3]/3
b[1, 1, 2, 2, 2, 2, 3, 3, 3] /b[1, 2, 3]
b[3, 2, 1, 2] == b[1, 2, 2, 3]
b[1, 2, 3] == b[1, 2, 2, 3]

Output:
b[1, 1, 2, 2, 2, 3, 4]
b[2, 4]
b[1, 3]
b[1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4]
b[1, 1, 3, 3]
b[1, 2]
b[3]
2
True
False

2

Q - 219 caratteri

a:(,)
s:{[x;y]x((!:)(#:)x)except(,/)({.[(#);x]}')flip(7h$(({(+/)x=y}[y]')(?:)y);(({where x=y}[x]')y))}
m:{(,/)$[0>(@:)x;(#[x]')y;(#[y]')x]}
d:{(?:)x(&:)({y<=(+/)x=z}[x;y]')x}
c:{min({(+/)x=y}[x]')y}
e:{(asc x)~asc y}

aper addizione, sper differenza (sottrazione), mper moltiplicazione, dper divisione, cper conteggio, eper uguaglianza.

L'algoritmo di aggiunta è quello ovvio, basta unire le borse.

La funzione di sottrazione si indicizza nel sacchetto di input (rappresentato come un array) con l'intero intervallo di indici, ad eccezione dei primi nindici di ciascuna classe di equivalenza formati dall'uguaglianza con ciascun elemento in y, dove nè il numero di copie di quel rappresentante in y. Gestire possibili duplicati in yrende questo un vero mostro di una funzione.

La funzione di moltiplicazione prende xvalori da ciascuno y, nel caso in cui ysia un singolo valore, anziché un array, li replica semplicemente.

La funzione di divisione produce i valori il cui conteggio nell'array è maggiore di y, quindi rimuove i duplicati.

La funzione di conteggio calcola i conteggi di ciascun elemento in y, quindi restituisce il minimo.

Due buste sono uguali se le loro rappresentazioni di array ordinate sono uguali.


2

Rubino, risposta definizione classe, 323 291 byte

Per lo più volevo solo rendere Baguna classe reale a causa della flessibilità di Ruby con le classi. In questo caso, eredita daArray perché è più breve di dover inizializzare un array interno e gestire le altre cose.

Probabilmente farò una risposta golfistica più seria che utilizza una funzione per gestire le operazioni domani. Sono molto stanco e mi sono divertito troppo con questo, anche se ho dovuto litigare con la definizione della classeNumber * Bag numerica per funzionare correttamente. PREMI LA FUNZIONE COERCE PER FARLO, NON HO BISOGNO DI INDOSSARE LE DEFINIZIONI DI CLASSE NUMERICHE

Provalo online! (Gli spazi bianchi non contano in Ruby, quindi il codice è leggermente ungolf lì.)

class B<Array
def == o
sort==o.sort
end
def + o
B.new super
end
def - o
r=to_a
o.map{|i|r[r.index(i)||size]=p}
B.new r-[p]
end
def * i
B.new super
end
def / i
B.new uniq.map{|o|[o]*(count(o)/i)}.flatten
end
def c o
o.map{|i|count i}.min
end
def inspect
sort
end
def coerce o
[self,o]
end
end

1

Rubino, 201 byte

Come promesso nella mia altra risposta, eccone uno che utilizza le funzioni invece di creare una nuova classe. Sono così vicino a violare il segno di 200 byte ... Provalo online

Questo utilizza gli stessi codici operativi di @Neil nella sua risposta JavaScript e lo stesso ordine di argomenti (lhs, opcode, rhs)

0: Addition
1: Difference
2: Multiplication
3: Division
4: Counting
5: Equality

Il codice:

->x,o,y{[->{(x+y).sort},->r=[*x]{y.map{|i|r[r.index(i)||x.size]=p};r-[p]},->{(x==[*x]?x*y :y*x).sort},->{x.uniq.map{|i|[i]*(x.count(i)/y)}.flatten},->{y.map{|i|x.count i}.min},->{x.sort==y.sort}][o][]}

1

C ++, 555 551 byte

(interruzioni di riga aggiunte per leggibilità - è richiesta e conteggiata solo la prima riga nuova)

#include<map>
struct B:std::map<int,int>{
B(std::initializer_list<int>l){for(auto i:l)++(*this)[i];}};
B operator+(B a,B b){for(auto m:b)a[m.first]+=m.second;return a;}
B operator-(B a,B b){for(auto m:b){int&x=a[m.first];x-=x>m.second?m.second:x;if(!x)a.erase(m.first);};return a;}
B operator*(B b,int n){for(auto m:b)b[m.first]*=n;return b;}
B operator*(int n,B b){return b*n;}
B operator/(B b,int n){for(auto m:b)if(!(b[m.first]/=n))b.erase(m.first);return b;}
int operator/(B a,B b){auto r=~0u;for(auto m:b){int x=a[m.first]/m.second;r=r>x?x:r;}return r;}

Spiegazione

Implementiamo la nostra borsa come una mappa di (valore, conteggio). Le operazioni di base possono essere implementate manipolando i conteggi; sottrazione e divisione di interi devono anche rimuovere tutti gli elementi il ​​cui conteggio raggiunge lo zero, quindi std::map::operator==funzionerà come test di uguaglianza.

Il seguente codice espanso è una versione generica di quanto sopra, molto meno golfato: ne utilizziamo uno separato s()per eliminare qualsiasi valore di conteggio zero e implementiamo le constoperazioni in termini di operatori di assegnazione nel modo idiomatico C ++. Usiamo anche s()per fare moltiplicazioni 0restituendo un sacchetto veramente vuoto (testato aggiungendo (B{1}*0 != B{})a main()); l'originale non supera questo test e non è chiaro se si tratti di un requisito.

template<class T>
struct Bag{
    std::map<T,int>b;
    Bag(const std::initializer_list<T>& l){for(auto i:l)++b[i];}
    Bag&s(){for(auto i=b.begin();i!=b.end();i=i->second?++i:b.erase(i));return*this;}
    Bag&operator+=(const Bag& o){for(auto m:o.b)b[m.first]+=m.second;return*this;}
    Bag&operator-=(const Bag& o){for(auto m:o.b){auto&x=b[m.first];x-=x>m.second?m.second:x;}return s();}
    Bag&operator*=(int n){for(auto m:b)b[m.first]*=n;return s();}
    Bag&operator/=(int n){for(auto m:b)b[m.first]/=n;return s();}
    auto operator/=(const Bag& o){auto r=~0u;for(auto m:o.b){int x=b[m.first]/m.second;r=r>x?x:r;}return r;}
    bool operator==(const Bag& o)const{return b==o.b;}

    Bag operator+(Bag o)const{return o+=*this;}
    Bag operator-(const Bag& o)const{Bag t=*this;return t-=o;}
    Bag operator*(int n)const{Bag t=*this;return t*=n;}
    friend Bag operator*(int n,const Bag& b){return b*n;}
    auto operator/(auto n)const{Bag t=*this;return t/=n;}
    bool operator!=(const Bag& o)const{return b!=o.b;}
};

using B = Bag<int>;

test

bool operator!=(B a,B b){return!(a==b);}
int main()
{
    return 0
        + (B{1,2,2,3}+B{1,2,4}  !=  B{1,1,2,2,2,3,4})
        + (B{1,2,2,4}-B{1,2}  !=  B{2,4})
        + (B{1,2,3}-B{2,4}  !=  B{1,3})
        + (B{1,2,3,3,4}*3  !=  B{1,1,1,2,2,2,3,3,3,3,3,3,4,4,4})
        + (2*B{1,3}  !=  B{1,1,3,3})
        + (B{1,1,2,2,2}/2  !=  B{1,2})
        + (B{1,2,2,3,3,3}/3  !=  B{3})
        + (B{1,1,2,2,2,2,3,3,3}/B{1,2,3} != 2)
        + (B{3,2,1,2}  !=  B{1,2,2,3})
        + (B{1,2,3}  ==  B{1,2,2,3})
        ;
}

Bella risposta! +1. Il tuo codice necessita di una corretta formattazione nel post.
Yytsi,

Volevo volutamente racchiudere il codice, così puoi vederlo tutto. L'alternativa era aggiungere interruzioni di riga.
Toby Speight,

1
Interruzioni di riga aggiunte: penso che sia meglio, perché ora funziona ora.
Toby Speight,

1

Python 2.7 - 447B (dimensione file)

Questo è il mio primo tentativo con Codegolf, spero che sia soddisfacente. Ho avuto bisogno di 2 ore. (Ma sono ancora un principiante in Python)

Modifica: Grazie a "Kevin Lau - non Kenny" per aver sottolineato questi:

  • L'argomento personale di Pythons in una classe può essere sostituito da qualsiasi cosa
  • il rientro deve essere solo un singolo spazio
  • l'ordinamento incorporato - funktion (lo sapevo averlo visto, ma ho pensato che fosse un metodo nelle liste)
  • __ radd __ non è necessario (supporto comunque solo l'aggiunta di oggetti B (tipo Bag))

Modifica: Inoltre ho risparmiato spazio sostituendo le funzioni con lambdas e nuove righe e rientri con più punti e virgola.

Codice:

class B:
 def __init__(S,L=[]):S.L=sorted(list(L));S.p=lambda:[[i]*S.L.count(i)for k,i in enumerate(S.L)if i!=S.L[k-1]];S.__eq__=lambda o:S.L==o.L;S.__rmul__=S.__mul__=lambda o:B(S.L*o);S.__add__=lambda o:B(S.L+o.L);S.__sub__=lambda o:B([i for k in S.p()for i in k[:max(0,S.L.count(k[0])-o.L.count(k[0]))]]);S.__div__=lambda o:B([i for k in S.p()for i in k[::o][:[-1,None][len(k)%o==0]]]);S.c=lambda o:min([S.L.count(i)//o.L.count(i)for i in o.L])

controlli:

print B([1,2,2,3]) + B([1,2,4]) == B([1,1,2,2,2,3,4]) # Add

print B([1,2,2,4]) - B([1,2]) == B([2,4]) #Substract
print B([1,2,3])   - B([2,4]) == B([1,3]) #Substract

print B([1,2,3,3,4]) * 3 == B([1,1,1,2,2,2,3,3,3,3,3,3,4,4,4])#Multiply
print 2 * B([1,3]) == B([1,1,3,3])                            #

print B([1,1,2,2,2])   /2 == B([1,2]) #Divide
print B([1,2,2,3,3,3]) /3 == B([3])   #

print B([1,1,2,2,2,2,3,3,3]).c(B([1,2,3]))==2 #Contained n times

print B([3,2,1,2]) == B([1,2,2,3]) # Equal
print B([1,2,3])   == B([1,2,2,3]) # Unequal

Produzione:

True
True
True
True
True
True
True
True
True
False

Potrei provarlo un'altra volta con set come base qualche volta. Modifica: forse proverò anche solo con le funzioni.


Benvenuti in PPCG! Una cosa da notare su Python è che in realtà non è necessario chiamare i primi parametri nelle funzioni di classe self- qualcosa del genere Sfarebbe altrettanto. Un altro trucco è che la sortedfunzione integrata fa esattamente quello che vuoi dalla tua nuova funzione s, quindi puoi rinunciare alla definizione della funzione (visto che la usi solo una volta). Non hai mai bisogno __radd__perché non aggiungi mai non-bag con borse, anche se hai ancora bisogno __rmul__. Infine, hai solo bisogno di uno spazio di rientro invece di quattro, che riduca il conteggio dei byte di un bel po '
Value Ink
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.