Реализация операций с сумками


20

Мешок , также называемый мультимножеством, это неупорядоченная коллекция. Вы можете назвать это набором, который допускает дублирование, или списком (или массивом), который не упорядочен / не проиндексирован. В этом задании вас попросят реализовать операции с сумками: сложение, разность, умножение, деление, подсчет и тест на равенство.

операции

Указанные операции могут быть не традиционными.

  • сложение объединяет две сумки в одну, сохраняя общее количество каждого значения
    [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]
  • деление является необычным: каждый n равных элементов помещается в n одинаковых новых сумок, элементы, которые не могут образовывать n-группу, остаются в сумке. Верните любую из n новых сумок.
    [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
  • проверка на равенство проверяет, имеют ли две сумки одинаковые номера для каждого элемента
    [1,2,2,3] == [3,2,1,2] = truthy [1,2,3] == [1,2,2,3] = falsy(также можно использовать =для этого)

Если вы используете свои собственные символы для операторов, пожалуйста, укажите.

Форматы

Сумки будут отображаться в виде списков формы [1,1,2,3,4]. Вы можете использовать любые другие скобки, кроме квадратных, или даже использовать кавычки, или вообще ничего. Элементы будут целыми числами (математически, не обязательно int) для целей этого вопроса. Сумки не должны быть отсортированы.

Формат ввода будет два пакета или мешок и целое число с оператором. Вы можете указать свой собственный формат, если он содержит эти три.

Формат вывода должен быть один мешок одного и того же формата.

правила

  • Вы не можете использовать встроенные функции, операции или библиотеки (включая стандартную библиотеку), которые уже реализуют их; Впрочем, можно использовать конкатенацию и умножение списков, поскольку они по определению являются операциями со списками, а не с сумками (которые в основном выполняют одно и то же).
  • применяются стандартные лазейки
  • самый короткий ответ выигрывает

Контрольные примеры

[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
Может быть, ослабить формат ввода? Например, можно использовать сумку, сумку / номер и оператора в качестве отдельных аргументов или в произвольном формате. В противном случае важной частью задачи является анализ входных данных, что не особенно интересно
Луис Мендо

Для анализа этого достаточно @LuisMendo split-on-space, если у вас есть язык, который вообще может оценивать строки как списки, не так ли? Я неопытен в публикации
заданий

Я не мог найти соответствующий мета пост, но смотри, например , формулировка здесь : вы можете прочитать целое как его десятичное представление, одинарного представление ( с использованием символа вашего выбора), массив байтов (большой или маленький Endian) или один байт (если это ваш тип данных самый большой язык) . Или здесь : форматы ввода и вывода, как обычно, гибкие (массивы, списки, список списков, строки с разумными разделителями и т . Д. ).
Луис Мендо

@LuisMendo сейчас в основном бесплатно. А про целое число я просто имел ввиду, что в математическом смысле, а не тип данных.
Busukxuan

1
@ LuisMendo Нет, символы должны иметь смысл, хотя бы немного. Ну, вы можете использовать один = для теста на равенство.
Busukxuan

Ответы:


3

05AB1E, 92 87 83 82 77 байт

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

Разделить по операции

>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

объяснение

прибавление

‚˜,}

Положите одну сумку в другую и сгладьте их в одну сумку.

умножение

и˜Qis}

Убедитесь, что номер находится на вершине стека. Назовите это X.

GD})˜,}

Дублируйте сумку X раз и соедините в одну сумку.

подсчитывать

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

Для каждого элемента в сумке делителя подсчитайте количество случаев в сумке дивидендов.
Минимальным количеством будет количество сумок, которые мы можем сделать.

равенство

 {s{Q,}

Сортируйте обе сумки и проверьте, равны ли они.

разделение

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

Посчитайте, сколько раз каждый уникальный элемент встречается в сумке.
Если это происходит как минимум столько раз, сколько делитель. Храните (nr_of_copies_total // divisor) копии в сумке.

разница

svy†¬yQi¦}} 

Для каждого элемента в вычитаемом элементе сортируйте его перед передней частью минюенда.
Если текущее вычитаемое значение равно первому элементу в minuend, удалите его из minuend.


9

APL (155)

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

Это определяет оператор 'bag', который определяет операции bag для заданных функций. Т.е.+∆ было бы дополнение. Затем он читает строку с клавиатуры и оценивает ее как выражение APL.

Функции:

  • +∆, дополнение
  • -∆вычитание
  • ×∆, умножение
  • ÷∆, подразделение
  • ⊂∆, считая
  • ≡∆, эквивалентность (хотя из-за игры в гольф любая нераспознанная функция сделает эквивалентность)

Объяснение:

  • ∆←{... }: определить оператор :

    • O←⍺⍺: сохранить данную функцию в O( ⎕CRне будет работать ⍺⍺напрямую)
    • O←⎕CR'O': получить строковое представление этой функции
    • '+'=O... :: для дополнения,
      • ⍺,⍵: объединить два списка
      • R[⍋R←... ]: и отсортировать результат
    • '-'=O:: для вычитания,
      • ⍺{...}⍵ : запустить следующую рекурсивную функцию:
        • ⍵≡⍬:⍺: если вычитаемое поле пусто, вернуть миненд
        • ⍺/⍨(⍳⍴⍺)≢⍺⍳⊃⍵∇1↓⍵: в противном случае удалите первый элемент вычитаемого и из вычитаемого, и из уменьшающегося и попробуйте снова
    • (⍬=⍴⍵)∧K←'×'=O: для умножения, и если правильный аргумент не является сумкой:
      • ⍵/⍺: реплицировать каждый элемент левого аргумента правым аргументом
    • K:... и если правильный аргумент - сумка:
      • ⍺/⍵: реплицировать каждый элемент в правом аргументе по левому аргументу (так, чтобы умножение было коммутативным)
    • '÷'=O:: для деления,
      • ⍵≤⍺∘.+⍺: посмотреть, какие элементы в ⍺ встречаются не менее ⍵ раз,
      • ⍺/⍨: выберите те из ⍺,
      • : и удалите все дубликаты из этого списка
    • '⊂'=O:: для подсчета,
      • ⍵{...}⍺ : запустить следующую рекурсивную функцию:
        • (∪⍺)≢∪⍵:0: если один список содержит элементы, а другой нет, результат равен 0
        • 1+⍺∇⍵-∆⍺: в противном случае вычтите дивиденды из делителя, повторите попытку и увеличьте результат.
    • : если ничего из вышеперечисленного, сделать тест на эквивалентность:
      • ⍺[⍋⍺]≡⍵[⍋⍵]: отсортировать оба списка и посмотреть, равны ли они
  • : прочитать выражение с клавиатуры, оценить его и вывести результат.

Тестовые случаи:

      ∆←{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

Действительно профессиональное решение и отличная рецензия! +1

Ваша рецензия и объяснения действительно твердые! Хотя, одно дело: для деления, я полагаю, что спецификация сформулирована так, как [2,2,2,2,2,2]/3должно [2,2], но ваша, похоже, дает [2].
Чернила стоимости

Вам не нужно кодировать REPL. Если вы просто определите , пользователь будет выгружен в собственный REPL APL, где теперь действует. Я думаю, что вы можете сохранить несколько байтов, переместив вычитание до конца, так как это единственный, который требует две строки. Вместо ⎕CR, используйте, *чтобы символизировать count, и сделать O←⍺⍺2, затем 2=O:для плюс, 1=Oдля mult, 0=O:для эквивалентных, 7<O:для count и 0<O:для div (с подразумеваемым 0>O:для subtr).
Адам

6

JavaScript (ES6), 260 байт

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

Принимает 3 параметра. Первый параметр - это массив, второй - оператор, третий зависит от оператора. Сумки должны содержать неотрицательные целые числа.

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

Октава, 253 244 226 байт

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

Эта функция должна быть в файле. Чтобы написать функцию в командном окне, вы должны использовать endfunctionили end.

Спасибо Луису Мендо за сохранение 18 байт.

Операции:

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

Пример использования:

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

Mathematica, 387 347 300 284 байта

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]

Слегка деголфированный (он же старая версия), не имел полной поддержки тестов на равенство (вернул истинные значения, но оставил без оценки для несоответствующих сумок).

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)

Реализует требуемый тип данных с головой b.

Первый bопределяется как Orderless. Любой объект, переданный ядру с головой, bбудет автоматически сортировать его аргументы. Таким образом, даже если b[3,2,1]он введен, оценщик никогда не увидит ничего, кроме b[1,2,3].

Дополнение тривиально определяется как объединение элементов.

Определено специальное правило для различия двух сумок (объяснено ниже). Предыдущая версия имела вспомогательный символ для выражений формы -bag.

Затем умножение (при условии, что nоно является положительным целым числом) рекурсивно определяется как то, n*b[...] = b[...] + (n-1)*b[...]которое в конечном итоге сводится к простой сумме.

Специальное правило для b[...] - b[...]подсчитывает количество различных элементов в сумке сумок и вычитает сумку, которая будет вычтена дважды из этого результата. Проще объяснить:

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

Выше список Keys->Values. KeyValueMapс Tableсоздает списки каждый Key Valueраз. (есть также, Max[...,0]чтобы не пытаться создавать таблицы отрицательной длины). Это выходит как:

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

который сплющен и голова Listзаменена на b.

Деление на целые числа несколько похоже на используемые функции, это просто поэтапное деление числа элементов на целое число.

Деление по наборам или подсчетам Я изменился с момента первоначальной реализации. Сейчас это делается рекурсивно следующим образом. Скажем, мы делим сумку b1на b2(что в коде гольфа есть cи aсоответственно. Если (b1-b2) + b2 == b1, тогда добавьте 1 и добавьте к этому результат деления (b1-b2)/b2. Если нет, верните 0 и выйдите из рекурсии.

Если сумки совпадают, встроенный ==дает True. Последняя строка заставляет, Falseесли они этого не делают.

Тестовые случаи:

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 символов

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}

aдля сложения, sдля разности (вычитания), mдля умножения, dдля деления, cдля подсчета, eдля равенства.

Алгоритм сложения очевиден, он просто объединяет сумки.

Функция вычитания индексирует во входной сумке (представленной в виде массива) весь диапазон индексов, за исключением первых nиндексов каждого класса эквивалентности, образованных равенством для каждого элемента в y, где nнаходится число копий этого представителя в y. Обработка возможных дубликатов yделает это настоящим монстром функции.

Функция умножения получает xзначения от каждого y, в случае, если yэто одно значение, а не массив, она просто копирует их.

Функция деления создает значения, количество которых в массиве больше, чем y, а затем удаляет дубликаты.

Функция подсчета вычисляет количество каждого элемента в y, а затем возвращает минимум.

Две сумки равны, если их отсортированные представления массива равны.


2

Ruby, ответ на определение класса, 323 291 байт

В основном просто хотел сделать Bagреальный класс из-за гибкости Ruby с классами. В этом случае он наследуется отArray что он короче, чем инициализация внутреннего массива и работа с другими вещами.

Я, вероятно, сделаю более серьезный ответ о гольфе, который использует функцию, чтобы справиться с операциями завтра. Я очень устал, и мне было очень весело с этим, хотя мне приходилось спорить с определением числового класса, чтобы Number * Bagправильно работать ХОЧИТЕ ФУНКЦИЮ COERCE, ЧТОБЫ ЭТО СДЕЛАТЬ, ЧТОБЫ Я НЕ ДОЛЖЕН БЫТЬ ПОВТОРЯТЬ ОПРЕДЕЛЕНИЯ КЛАССА ЧИСЛА

Попробуйте онлайн! (Пробелы в Ruby не имеют значения, поэтому код там немного раскручен.)

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

Рубин, 201 байт

Как и было обещано в моем другом ответе, вот тот, который использует функции вместо создания нового класса. Я так близок к преодолению 200-байтовой отметки ... Попробуйте онлайн

При этом используются те же коды операций, что и @Neil в его ответе JavaScript, и тот же порядок аргументов (lhs, код операции, rhs)

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

Код:

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

С ++, 555 551 байт

(разрывы строк добавлены для удобства чтения - требуется только первая новая строка и считается)

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

объяснение

Мы реализуем нашу сумку в виде карты (значение, количество). Основные операции могут быть реализованы путем манипулирования счетами; вычитание и целочисленное деление также должны удалить любые элементы, чье количество достигает нуля, так что это std::map::operator==будет работать в качестве теста на равенство.

Следующий расширенный код является общей версией вышеупомянутого, гораздо менее сложного: мы используем отдельное s()для выжимания любых значений с нулевым счетом, и мы реализуем constоперации в терминах операторов присваивания идиоматическим способом C ++. Мы также используем s()для умножения путем 0возврата действительно пустой пакет (проверено путем добавления (B{1}*0 != B{})к main()); оригинал не проходит этот тест, и неясно, является ли это требованием.

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

тесты

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

Хороший ответ! +1. Ваш код нуждается в правильном форматировании в посте.
Yytsi

Я намеренно хотел обернуть код, чтобы вы могли видеть все это. Альтернативой было добавить разрывы строк.
Тоби Спейт

1
Добавлены разрывы строк - я думаю, что это лучше, потому что теперь работает prettify.
Тоби Спейт

1

Python 2.7 - 447B (размер файла)

Это моя первая попытка в Codegolf, надеюсь, это удовлетворит. Мне нужно 2 часа. (Но я все еще начинающий в Python)

Изменить: Спасибо "Кевин Лау - не Кенни" за указание на это:

  • сам аргумент питонов в классе может быть заменен на что угодно
  • отступ должен быть только один пробел
  • встроенный отсортированный - функционал (я знал что видел это, но я думал, что это был метод в списках)
  • __ radd __ не нужен (я все равно поддерживаю только добавление B-объектов (типа Bag))

Изменить: Кроме того, я сэкономил место, заменив функции с лямбда-выражений и новые строки и отступы с большим количеством точек с запятой.

Код:

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

проверки:

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

Выход:

True
True
True
True
True
True
True
True
True
False

Я мог бы попробовать это в другой раз с установленным в качестве основы некоторое время. Редактировать: Может быть, я даже попробую только с функциями.


Добро пожаловать в PPCG! В Python следует обратить внимание на то, что на самом деле вам не нужно вызывать первые параметры в функциях класса self- как Sи в случае с ними. Другой трюк заключается в том, что встроенная sortedфункция делает именно то, что вы хотите от вашей новой функции s, так что вы можете отказаться от определения функции (видя, что вы используете ее только один раз). Вам никогда не нужно, __radd__потому что вы никогда не добавляете не сумки с сумками, хотя вам все еще нужно __rmul__. Наконец, вам нужен только один пробел отступа вместо четырех, что значительно сокращает количество байтов
Value Ink
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.