Видаліть оточуючі нулі 2d масиву


40

Це двовимірна версія цього питання .

Дано не порожній двовимірний масив / матрицю, що містить лише невід'ємні цілі числа:

[0000000010000010011100000]

Вивести масив із оточеними нулями, тобто найбільшим суміжним масивом без оточуючих нулів:

[010001111]

Приклади:

[0000000010000010011100000][010001111]
Input:
[[0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0]]

Output:
[[0, 1, 0], [0, 0, 1], [1, 1, 1]]

[00000003000005000000][003000500]
Input:
[[0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0], [0, 5, 0, 0], [0, 0, 0, 0]]

Output:
[[0, 0, 3], [0, 0, 0], [5, 0, 0]]

[123456789][123456789]
Input:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Output:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

[000000000000][]
Input:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Output:
[]

[000011110000][1111]
Input:
[[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]]

Output:
[[1, 1, 1, 1]]

[010001000100][111]
Input:
[[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]

Output:
[[1], [1], [1]]

[111112311111][111112311111]
Input:
[[1, 1, 1, 1], [1, 2, 3, 1], [1, 1, 1, 1]]

Output:
[[1, 1, 1, 1], [1, 2, 3, 1], [1, 1, 1, 1]]

3
@MattH Ніщо не складне в неезотеричній мові. :)Просто важко зробити це коротким.
користувач202729

1
Чи можемо ми дати остаточний результат фальси замість порожньої матриці для останнього тестового випадку?
sundar

1
Крім того, якщо вихід може бути не квадратною матрицею, будь ласка, додайте для цього тестовий випадок.
sundar

1
Тестовий випадок, який порушив моє попереднє подання: [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0]](результат має ширину / висоту 1)
Conor O'Brien

1
Гей, чи можна додати тестовий випадок
[111112311111]
Beta Decay

Відповіді:



39

Мова Вольфрама (Mathematica) , 42 байти

#&@@CellularAutomaton[{,{},0{,}},{#,0},0]&

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

Стільникові автомати - це дійсно відповідь на життя , Всесвіт та все . 1

Як?

CellularAutomatonприймає вхідний масив і необов'язкове фонове значення. Таким чином, {#,0}вказується, що до вхідного сигналу слід застосовувати правило стільникового автомата, припускаючи фон 0s.

Акуратне тут полягає в тому, що CellularAutomatonобробляє вихід таким чином, щоб не було меж фонових комірок (бо в іншому випадку вихід лежить на нескінченній площині).

У коді застосовується правило {Null, {}, {0, 0}}- прикладання головки Nullдо 0-радіусного сусіда кожної комірки (тобто лише до центру: сама комірка) - рівно в 0рази. Результатом цього є вихідний вхід, але з фоном видалено (тобто обрізання оточуючих 0).


1. Бачите обліковий запис моєї відповіді? ;)


6
Приємне зловживання вбудованим ... ну і Mathematica має вбудований, просто не піддається впливу.
користувач202729

3
Немає посилання на XKCD 505 ?
Esolanging Fruit

+1 для стільникових автоматів та остаточний відповідь.
HighlyRadioactive

14

JavaScript (ES6), 98 байт

(a,z)=>(g=A=>A.slice(A.map(m=M=(r,i)=>M=(z?a:r).some(n=>z?n[i]:n)?1/m?i:m=i:M)|m,M+1))(a).map(z=g)

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

Як?

Щоб подолати відсутність вбудованої zip , ми визначимо функцію g (), яка здатна працювати або на рядках, або на стовпцях вхідної матриці a [] , залежно від значення глобального прапора z .

g () шукає мінімальний індекс m та максимальний індекс M або непорожніх рядків (якщо z не визначено), або непусті стовпці (якщо z визначено z ) та повертає відповідний фрагмент або самої матриці, або заданого рядка матриці.

Узагальнити:

  • ми спочатку видаляємо рядки, викликаючи g () на матриці з z undefined
  • Потім ми видаляємо стовпці, викликаючи g () у кожному рядку з визначеним z , що призводить до цього досить незвично.map(z=g)

Прокоментував

(a, z) => (               // a[] = input matrix; z is initially undefined
  g = A =>                // g() = function taking A = matrix or row
    A.slice(              //   eventually return A.slice(m, M + 1)
      A.map(m = M =       //     initialize m and M to non-numeric values
        (r, i) =>         //     for each row or cell r at position i in A:
        M = (z ? a : r)   //       iterate on either the matrix or the row
        .some(n =>        //       and test whether there's at least one
          z ? n[i] : n    //       non-zero cell in the corresponding column or row
        ) ?               //       if so:
          1 / m ? i       //         update the maximum index M (last matching index)
                : m = i   //         and minimum index m (first matching index)
        :                 //       otherwise:
          M               //         let M (and m) unchanged
      ) | m,              //     end of map(); use m as the first parameter of slice()
      M + 1               //     use M+1 as the second parameter of slice()
    )                     //   end of slice()
  )(a)                    // invoke g() on the matrix with z undefined
  .map(z = g)             // invoke g() on each row of the matrix with z defined

2
Це вражає.
Джек Хейлз

3
@Jek, Арнольд живе в зовсім іншому вимірі. Але якщо вам надзвичайно пощастило, ви можете час від часу знаходити хитрість, яку він пропустив, і розмістити коротше рішення. У процесі цього ви розвинете дуже глибоке розуміння JavaScript.
Рік Хічкок

4
@ RickHitchcock Я не такий хороший у розпізнаванні кодового шаблону, і я регулярно пропускаю багато речей, навіть якщо я їх бачив раніше. У цьому конкретному прикладі я був зосереджений на повторному використанні g () і пропустив цілком очевидну оптимізацію щодо оновлення m та M (-9 байт). Я повністю погоджуюся, що кодовий гольф - це чудовий (і цікавий) спосіб дізнатися багато про тонкощі мови.
Арнольд

7

Haskell , 62 61 байт

f.f.f.f
f=reverse.foldr(zipWith(:))e.snd.span(all(<1))
e=[]:e

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

foldr(zipWith(:))eз e=[]:eце трохи коротшеtranspose , і snd.span(all(<1))краплі , що ведуть списки нулів зі списку списку. Після transposeцього reverseу двовимірному списку дорівнює обертання на 90 °, код f.f.f.fлише чотири рази скидає провідні списки нулів і обертається .




5

Брахілог , 24 22 20 19 байт

{s.h+>0∧.t+>0∧}\↰₁\

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

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

(Завдяки @Fatalize за пропозицію вбудованого предиката та збереження 1 байта.)

Пояснення

Предикат 0 (головний):

{...}     Define and call predicate 1 to remove all-zero rows
  \       Transpose the result
   ↰₁     Call pred 1 again, now to remove all-zero columns
     \    Transpose the result to have correct output orientation

Предикат 1:

?s.h+>0∧.t+>0∧
  .           output is
 s              a subsequence of the rows of
?              the input (implicit)
   h          also, output's head element (first row)
    +>0        has a sum > 0 (i.e. has at least one non-zero value)
       ∧.t+>0  and similarly the output's tail element (last row)
∧              (don't implicitly unify that 0 with the output)

Записавши перший предикат вбудований в 1 байт коротше: {s.h+>0∧.t+>0∧}\↰₁\ . (це стосується майже будь-якої відповіді Брахілога, предикати в нових рядках реально реалізуються лише у тому випадку, якщо ви хочете написати більше читаних речей).
Фаталізувати

@Fatalize Спасибі, оновлено (нарешті!). Я ніколи не замислювався над тим, як синтаксис вбудованого предиката є і визначенням, і застосуванням предиката, досить класно.
sundar

5

R , 96 100 97 байт

function(m)m[~m,~t(m),drop=F]
"~"=function(x,z=seq(r<-rowSums(x)))z>=min(y<-which(r>0))&z<=max(y)

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

~Помічник приймає невід'ємні вектор і повертає вектор з FALSEдля «зовнішнього вигляду» 0S вектора і TRUEдля позитивів і будь-якого «інтер'єру» 0с. Ця функція застосовується до сум рядків і стовпців вхідної матриці.

~і ! використовувати R-синтаксичний аналіз операторів.

Виправлено відповідно до коментаря @ DigEmAll, але з деякими байтами, відібраними від @ J.Doe


1
Я думаю, ви повинні додати drop=Fяк я, інакше ці 2 тести повернуть вектор замість рядка та стовпця: Спробуйте в Інтернеті!
digEmAll

97 байт с drop=F. Ще під тонну!
J.Doe

5

R , 89 79 байт

function(m,y=apply(which(m>0,T),2,range)){y[!1/y]=0;m[y:y[2],y[3]:y[4],drop=F]}

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

Дякуємо @ngm за код тестових випадків та @ J.Doe за збереження 10 байт!

  • Мені довелося додати drop=Fпараметр через поведінку R за замовчуванням, перетворюючи матрицю одного рядка / кола у вектори ...

Я не помітив, що мій попередній код
провалював

1
Я хотів би, щоб я міг +2 цього. Дійсно приємне використання п'ятиріччя.
JayCe

79 байт із використанням rangeта налаштуванням індексації
J.Doe

1
@ J.Doe: діапазон, звичайно! чудова ідея спасибі!
digEmAll


3

Python 2 , 71 байт

Повертається шляхом зміни вводу. Список повинен бути переданий як вхідний.

def f(a):exec'while a and 1>sum(a[-1]):a.pop()\na[:]=zip(*a)[::-1]\n'*4

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


Python 2 , 77 байт

Це також змінює вхід, але він працює ....

def f(a):exec'while a and 1>sum(a[-1]):a.pop()\na=zip(*a)[::-1]\n'*4;return a

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





2

Лушпиння , 11 байт

!5¡(T0mo↔↓¬

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

Я відчуваю, що деякі байти можна побрити, скоротивши !5¡частину.

Як це працює

!5¡(

5th

mo↔↓¬

Зробити карту над поточною версією введення та: перевернути кожну, після того, як випав лише найдовший префікс, що містить нулі (викидання цього префікса виконується за допомогою Husk's , що є функцією, яка обробляє найдовший цикл послідовних елементів з початку список, який дає результати truthy при запуску через функцію, а саме ¬логічно немає).

T0

Перемістіть, замінивши відсутні записи в 0 .


2

Сітківка , 87 байт

/.\[(?!0,)/^+`\[0, 
[
/(?<! 0)]./^+`, 0]
]
\[(\[0(, 0)*], )+
[
(, \[0(, 0)*])+]|\[0]]
]

Спробуйте в Інтернеті! Пояснення:

/.\[(?!0,)/^+`

Поки хоча б один рядок не починається з нуля ...

\[0, 
[

... видалити нульовий нуль з кожного рядка.

/(?<! 0)]./^+`

Поки хоча б один рядок не закінчується нулем ...

, 0]
]

... видаліть кінцевий нуль з кожного рядка.

\[(\[0(, 0)*], )+
[

Видаліть провідні ряди нулів.

(, \[0(, 0)*])+]|\[0]]
]

Видаліть кінцеві ряди нулів або останній нульовий нуль.


1
@RickHitchcock Це чутливий формат, додайте пробіли: Спробуйте в Інтернеті!
Ніл

2

Вугілля деревне , 48 байт

F⁴«W∧θ¬Σ§θ±¹Σ⊟θ¿θ≔⮌E§θ⁰E觧θνλθ»⪫[]⪫Eθ⪫[]⪫ι, ¦, 

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Включає 15 байт для форматування. Пояснення:

F⁴«

Повторіть 4 рази.

W∧θ¬Σ§θ±¹

Повторіть, поки масив не порожній, але останній рядок дорівнює нулю ...

Σ⊟θ

Видаліть останній рядок із масиву та надрукуйте рядок довжиною його суми, тобто нічого.

¿θ≔⮌E§θ⁰E觧θνλθ»

Якщо масив не порожній, тоді перенесіть його.

⪫[]⪫Eθ⪫[]⪫ι, ¦, 

Відформатуйте масив добре для відображення. ( IθЗамість цього буде стандартний вихід .)


2

JavaScript, 144 140 129 127 байт

w=>(t=w=>(q=(s=w=>w.some((r,j)=>r.find(e=>e,i=j))?w.slice(i).reverse():[[]])(s(w)))[0].map((e,j)=>q.map((e,i)=>q[i][j])))(t(w))

140 -> 129 байт, дякую @Arnauld

Алгоритм

  • Зробіть двічі:
    • Знайдіть перший ненульовий рядок
    • Зріжте попередні ряди
    • Зворотний
    • Знайдіть перший ненульовий рядок
    • Зріжте попередні ряди
    • Зворотний
    • Перенести

f = w=>(t=w=>(q=(s=w=>w.some((r,j)=>r.find(e=>e,i=j))?w.slice(i).reverse():[[]])(s(w)))[0].map((e,j)=>q.map((e,i)=>q[i][j])))(t(w));

w1 = [[0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, 0, 1, 1, 1], [0, 0, 0, 0, 0]];
w2 = [[0, 0, 0, 0], [0, 0, 0, 3], [0, 0, 0, 0], [0, 5, 0, 0], [0, 0, 0, 0]];
w3 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
w4 = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

console.log(f(w1).join("\n"));
console.log(f(w2).join("\n"));
console.log(f(w3).join("\n"));
console.log(f(w4));


Ви можете зберегти 7 байтів , використовуючи some/someзамість findIndex/findі не переставляючи декларації допоміжної функції, щоб позбутися дужок навколо (тепер єдиного) основного аргументу функції.
Арнольд

Я думаю , що ви можете заощадити ще 4 байта , маючи s повернення , [[]]так що т гарантовано буде в змозі працювати на w[0].
Арнольд

2

Python 2 , 118 116 байт

f=lambda a,n=4,s=sum:n and f(zip(*a[max(i for i in range(len(a))if s(s(a[:i],()))<1):][::-1]),n-1)or(s(s(a,()))>0)*a

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


Збережено:

  • -2 байти, завдяки shooqie

1
Ви можете зберегти два байти, призначивши s=sumв лямбда-дефініції
shooqie

2

PHP (> = 5,4), 200 194 186 184 байт

(-6 байт шляхом повернення nullзамість порожнього масиву)

(-8 байт завдяки Титу )

(-2 байти з викликом за посиланням завдяки Тіту )

function R(&$a){$m=$n=1e9;foreach($a as$r=>$R)foreach($R as$c=>$C)if($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}for(;$m<=$M;)$o[]=array_slice($a[$m++],$n,$N-$n+1);$a=$o;}

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

Як?

Знаходить показник min та max для рядків ( $m& $M) та стовпців ( $n& $N) та замінює вхід під масивом sub $m,$nдо $M,$N(це дзвінок за посиланням).


Збережіть 6 байт за допомогоюif($C){$m>$r&&$m=$r;$M>$r||$M=$r;$n>$c&&$n=$c;$N>$c||$N=$c;}
Тітус

... і два байти зwhile($m<=$M)$o[]=array_slice($a[$m++],$n,$N-$n+1);
Титом

@Titus: Дякую за чудові поради. Полюбилася хитрість використання, &&і ||я впевнений, що зможу використовувати цей трюк і в інших місцях.
Ніч2

1
Ви можете зберегти ще два байти з викликом за посиланням: $a=замість return.
Тит



2

J , 24 байти

(|.@|:@}.~0=+/@{.)^:4^:_

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

Пояснення

(|.@|:@}.~0=+/@{.)^:4^:_
            +/                sum
              @               of
               {.             the first row
          0=                  is zero? (1 = true, 0 = false)
       }.~                    chop off that many rows from the front
 |.@|:@                       rotate by 90 deg (transpose then reverse)
(                )^:4         repeat this process 4 times (rotating a total of 360 deg)
                     ^:_      fixpoint - repeat until no change

2

Рубі , 73 63 байт

->a{4.times{_,*a=a while a[0]&.sum==0;a=a.reverse.transpose};a}

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

Редагувати: спрощено, попередня версія вийшла з ладу для всіх 0s

Як це працює:

  • робити 4 рази:
    • видаліть перший рядок, поки є перший рядок, і він заповнений 0s
    • обертати масив за годинниковою стрілкою на 90 °
  • повернути масив

Посилання правильне, але ваша відповідь у кодовому блоці говорить &.sum<0замість &.sum<1.
Conor O'Brien

@ ConorO'Brien моя погана, нова версія не працювала для порожнього масиву (нуль <1). Дякую за те, що все-таки помітили
Асона Тухід

1

Октава , 78 74 байти

function x=f(x)
for k=1:nnz(~x)*4,x=rot90(x);x=x(:,~~cumsum(any(x,1)));end

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

Пояснення

Це обертає матрицю на 90градуси ( x=rot90(x)) достатню кількість разів ( for k=1:... end). Кількість обертів кратно 4, тому кінцева матриця має оригінальну орієнтацію. Зокрема, кількість обертів в 4рази перевищує кількість нулів у матриці ( nnz(~x)*4).

Для кожного обертання, якщо зліва є один або кілька стовпців, що складаються лише з нулів, вони видаляються ( x=x(:,~~cumsum(any(x,1)))).

Що залишається від матриці після цього процесу, виводиться функцією ( function x=f(x)).



1

PHP, 188 байт

function f(&$a){for($s=array_shift;!max($a[0]);)$s($a);for($p=array_pop;!max(end($a));)$p($a);for($w=array_walk;!max(($m=array_map)(reset,$a));)$w($a,$s);while(!max($m(end,$a)))$w($a,$p);}

дзвінок за посиланням.

зламатися

// call by reference
function f(&$a)
{
    // while first row is all zeroes, remove it
    while(!max($a[0]))array_shift($a);
    // while last row is all zeroes, remove it
    while(!max(end($a)))array_pop($a);
    // while first column is all zeroes, remove it
    while(!max(array_map(reset,$a)))array_walk($a,array_shift);
    // while last column is all zeroes, remove it
    while(!max(array_map(end,$a)))array_walk($a,array_pop);
}


1

Python 2 , 86 байт

lambda a,l=1:a if l>4else([a.pop()for b in a if sum(a[-1])<1],f(zip(*a[::-1]),l+1))[1]

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

Бере список списків, повертає список кортежів.

Пояснення

Зловживає чортом поза розумінням списку. Це еквівалентний розширений код:

def f(a,l=1):
    # after 4 rotations, the list is back in its original orientation, return
    if l > 4:
        return a
    else:
        # helper variable to store return values
        ret = []
        # "trim" all rows from "bottom" of list that only contain 0s
        # since we are always checking le that item in the list, don't need range(len(a))
        # since we are only removing at most one item per iteration, will never try to remove more than len(a) items
        # brackets surrounding generator force it to be consumed make a list, and therefore actually pop() list items
        ret.append([a.pop() for b in a if sum(a[-1]) < 1])
        # rotate the array, increase the number of rotations, and recursively call this function on the new array/counter
        ret.append(f(zip(*a[::-1]), l + 1)))
        # we only put both items in a list in order to stay in the one-line lambda format
        # discard the popped items and return the value from the recursive call
        return ret[1]

1

Japt -h , 23 11 байт

4Æ=sUb_dà z

Спробуй це


Пояснення

                :Implicit input of 2D-array U
4Æ              :Map the range [0,4)
   s            :  Slice U from
    Ub          :   The first index in U where
      _dà      :    Any element is truthy (not zero)
          z     :  Rotate 90 degrees
  =             :  Reassign to U for the next iteration
                :Implicitly output the last element
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.