Determine if a given square binary matrix has exactly one row or column consisting of entirely 1s, and the rest of the matrix is 0s.
For example, these are all true:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1
And these are all false:
0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0
1 1 1 1 1 1 1 0 1 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
The reasons for the false ones:
- More than one row
- More than one row or column
- There are
1s outside the "all1s column" - There isn't a row or column of all
1s (describes the last 4)
You should take a square binary matrix of side length \$n \ge 2\$, in any reasonable format, and output 2 distinct, consistent values to indicate whether it has a single straight line. This is code-golf, so the shortest code in bytes wins.
Keep your golfing in your code, not your inputs/outputs. I'm very liberal with the I/O formats, including but not limited to:
- A multiline string
- A list of lines
- A 2D list (or matrix) consisting of two distinct consistent values (e.g.
0/1, space/'*',5/'(') - A flat array, and \$n\$, as separate arguments
- Two distinct consistent values (e.g.
1/0) to indicate the output - Erroring/not erroring
- Two families of values, one of which consists of values that are truthy in your language and the other falsey (for example, natural numbers and zero)
- etc.
As a broad, general rule, so long as the input can be clearly understood and the outputs clearly distinguished, it's fair game.
Test cases
| Input | Output |
|---|---|
|
true |
|
true |
|
true |
|
true |
|
false |
|
false |
|
false |
|
false |
|
false |
|
false |
|
false |
|
false |
-
1\$\begingroup\$ May we take \$n\$ along with a non-flat array? \$\endgroup\$chunes– chunes2021年06月17日 02:12:56 +00:00Commented Jun 17, 2021 at 2:12
-
2\$\begingroup\$ @chunes Yep, that's fine \$\endgroup\$caird coinheringaahing– caird coinheringaahing ♦2021年06月17日 02:16:07 +00:00Commented Jun 17, 2021 at 2:16
-
1\$\begingroup\$ suggested test case: a matrix with the right amount of ones but not in a line \$\endgroup\$MarcMush– MarcMush2021年06月17日 11:29:32 +00:00Commented Jun 17, 2021 at 11:29
-
3\$\begingroup\$ I really like this kind of problem, where at face value it's very simple, but ends up generating many conceptually different solutions, some involving higher math (matrix algebra in this case). \$\endgroup\$Jonah– Jonah2021年06月17日 12:41:31 +00:00Commented Jun 17, 2021 at 12:41
-
2\$\begingroup\$ Nice use of markdown tables for test cases. I should do that \$\endgroup\$qwr– qwr2021年06月17日 23:24:27 +00:00Commented Jun 17, 2021 at 23:24
26 Answers 26
Python 2, 49 bytes
Takes as input a 2D binary matrix \$ a \$, and its size \$ n \$.
lambda a,n:sorted(map(sum,a+zip(*a)))[-2:]==[1,n]
There may be shorter approaches, but this is what I could find for now. Please let me know if the algorithm is incorrect.
Explanation
Since there is exactly one line, there should be exactly one row/column which contains \$ n \$ ones. Furthermore, since every \$ 1 \$ in the matrix exists on that line, there can be no other row/column containing more than one \$ 1 \$. Since if there were another \$ 1 \$ existing somwhere not on that line, it would create a row/column with at least two \$ 1 \$s.
Given this, it suffices to check that the two rows/columns with the largest number of \$ 1 \$s have counts of [1, n].
-
\$\begingroup\$ @DLosc Brilliant idea! I had suspected my solution could be improved upon. Would you like to post a new answer? \$\endgroup\$dingledooper– dingledooper2021年06月17日 23:24:17 +00:00Commented Jun 17, 2021 at 23:24
-
\$\begingroup\$ All right, done! It's mostly your idea, so I wanted to give you the option of integrating it first. It is exciting to get to post a Python golf--normally my answer is both longer and later than other people's. ;^) \$\endgroup\$DLosc– DLosc2021年06月18日 17:27:13 +00:00Commented Jun 18, 2021 at 17:27
Brachylog, 8 bytes
{z|}≡v+1
{z|} Either the rows or the columns
≡v are all the same list
+1 which sums to 1.
-
2\$\begingroup\$ An alternate, ASCII-only version (same number of bytes): replace
≡vwith=h. \$\endgroup\$DLosc– DLosc2021年06月17日 22:22:24 +00:00Commented Jun 17, 2021 at 22:22
Ruby, 47 bytes
->m,n{m.uniq[1]?m-[[0]*n]==[[1]*n]:m[0].sum==1}
Explain please:
Split the two cases:
If m has at least 2 different rows, remove all zeros and check if we are left with a single row consisting of ones.
If not (all the rows are the same), check that the sum of the first row is one.
Factor + math.unicode, 59 bytes
[ [ concat Σ = ] keep dup flip [ all-equal? ] bi@ or and ]
Takes \$n\$ and a matrix of \1ドル\$s and \0ドル\$s, in that order.
[ concat Σ = ] keepIs the sum of the matrix equal to \$n\$?dup flip [ all-equal? ] bi@ or andAnd are all the rows in either the original matrix or its transposition equal?
JavaScript (ES6), 46 bytes
Thanks to @PertinentDetail for a bug fix
Expects a multiline string with a trailing line feed. Returns a Boolean value.
s=>/^(0*10*\n)1円*$|^(0+\n)*1+\n[^1]*$/.test(s)
-
3\$\begingroup\$ Unfortunately, this doesn't work if the ones are the first row of the matrix (not one of the test cases). To fix this, replace 2円* with [^1]* at the cost of two characters. However, you don't need the grouping in (1円+\n) so you can save two characters to get back to 46. \$\endgroup\$PertinentDetail– PertinentDetail2021年06月17日 21:35:37 +00:00Commented Jun 17, 2021 at 21:35
-
\$\begingroup\$ @PertinentDetail Good catch and nice fix. Thanks! \$\endgroup\$Arnauld– Arnauld2021年06月17日 21:57:18 +00:00Commented Jun 17, 2021 at 21:57
Jelly, 9 bytes
S;§ṢIṪ‘=L
Slightly modified port of dingledooper's algorithm.
How it works
S;§ṢIṪ‘=L Monadic link; input = matrix M
S;§ Column sums of M ++ Row sums of M
Ṣ Sort
I Increments; (next - previous) for each adjacent pair
Ṫ Last item
‘ +1
=L Equals the length of M?
Jelly, 9 bytes
×ばつSS=L
Slightly modified port of chunes's algorithm.
How it works
×ばつSS=L Monadic link; input = matrix M
ZE 1 if transpose(M) has all rows equal
ȯE or M has all rows equal, 0 otherwise
×ばつSS times column sum, and sum again
(= times the sum of the entire matrix)
=L equals the length of M?
Wolfram Language (Mathematica), (削除) 21 (削除ここまで) (削除) 13 (削除ここまで) 35 bytes
Norm@#==#2&&Norm@Eigenvectors@#>#2&
Try It Online! (Thanks to @ZaMoC for configuring this.)
Takes # as the matrix, and #2 as the square root of the side length, n. Returns True if the conditions are met, and False otherwise
Explanation
In Mathematica, the Norm function, when applied to a matrix, will perform a singular value decomposition and then identify and return, from among the resulting matrices, the element with the largest value. For most square binary matrices with n ≥ 2, the conditions will be met IFF the Norm of the matrix equals sqrt(n), i.e., if the following returns True:
Norm@#==#2&
However @Nitroden found an exception, which can be generalized as follows: If sqrt(n) is an integer, and the matrix contains a sqrt(n) x sqrt(n) submatrix that is all 1's, and has 0's everywhere else, its Norm will also equal sqrt(n).
Thus, to eliminate those, I added an additional test: that the Norm of the Eignevectors of the matrix is greater than sqrt(n).
My Try It Online! link contains all the OP's test matrices and, at the end, Norden's case plus three additional matrices of that form. These now all return False.
Alas, Mathematica's Eigenvectors function is 12 bytes.
Thanks to @Bubbler for the tip that my If wrapper was unnecessary.
-
3\$\begingroup\$ I think it should be fine to strip the if statement entirely (giving true or false). \$\endgroup\$Bubbler– Bubbler2021年06月17日 06:29:29 +00:00Commented Jun 17, 2021 at 6:29
-
\$\begingroup\$ I don't have mathematica but it seems like this only counts if there is the right amount of
1s Try it online with Julia! \$\endgroup\$MarcMush– MarcMush2021年06月17日 11:28:27 +00:00Commented Jun 17, 2021 at 11:28 -
\$\begingroup\$ @MarcMush I tried your test matrix, and it correctly returned
False. "norm" seems to means something different in Julia—according to discourse.julialang.org/t/performance-of-norm-function/14709/9, it instead computes the Frobenius norm. In Mathematica, whenNormis applied to a matrix, it does a singular value decomposition, and then selects the element with the maximum value. So, for your matrixm= {{1, 0, 0}, {1, 0, 0}, {0, 1, 0}}, [continued] \$\endgroup\$theorist– theorist2021年06月17日 11:56:45 +00:00Commented Jun 17, 2021 at 11:56 -
1\$\begingroup\$ here are all test cases: Try it online! \$\endgroup\$ZaMoC– ZaMoC2021年06月17日 12:04:31 +00:00Commented Jun 17, 2021 at 12:04
-
5\$\begingroup\$ Fails on
{{1, 1, 0, 0}, {1, 1, 0 ,0}, {0, 0, 0, 0}, {0, 0, 0, 0}, which has operator norm 2. \$\endgroup\$Nitrodon– Nitrodon2021年06月17日 13:55:03 +00:00Commented Jun 17, 2021 at 13:55
Vyxal, 12 bytes
:∑$v∑Js ̄Nt›=
Yay! Beating Lyxal by 1 byte with a different approach!!!
-1 byte from @Lyxal himself thanks
-
2\$\begingroup\$ You can remove
0for -1 (because the input hasn't cycled back to the input list) \$\endgroup\$2021年06月17日 04:17:11 +00:00Commented Jun 17, 2021 at 4:17 -
2\$\begingroup\$ Good job! You beat the creator of the language. \$\endgroup\$user100690– user1006902021年06月17日 05:15:21 +00:00Commented Jun 17, 2021 at 5:15
05AB1E, 8 bytes
Based on the first part of Bubblers Jelly answer, which uses dingledooper's algorithm.
Input is a 2d matrix and the side length, output is 1 for truthy inputs and any other integer for falsy ones. This is the definition of truthiness in 05AB1E.
Dø«O{\θα
Try it online! or Try all cases!
D # push two copies of the input matrix
ø # transpose one copy to get a list of columns
« # concatenate to the list of rows
O # sum each sublist
{ # sort the row and column sums
\ # take consecutive differences
θ # get the last one (largest value - second largest value)
α # absolute difference with the second input
Jelly, 10 bytes
S;§>Ƈ1=LW$
Uses Unrelated string's test suite.
Fixed with some help from Unrelated string.
Explanation
S;§>Ƈ1=LW$
S sums of columns
; concat with
§ sums of rows
Ƈ keep the sums which are:
> 1 greater than 1
=LW$ = [length] ?
Jelly, 9 bytes
ŒṪZEƇȧiɗJ
The fourth totally different Jelly 9 byter. Returns either 1 or 2 for truthy and either an empty list or the number 0 for falsy. Also the program structure is more convoluted.
How it works
ŒṪZEƇȧiɗJ Monadic link. Input: the matrix M of size n
ŒṪZ Take the transpose of multi-dimensional indices of 1
the result is a 2-row matrix X;
in order to satisfy the condition, one of the rows must be
all-equal, and the other must be identical to 1..n
....ɗJ A dyad with ^ as left arg and 1..n as right:
EƇ Collect every row that is all-equal from X
ȧ Chain onto Python's `and`...
i Get 1-based index of 1..n in X, 0 if not found
J, 25 bytes
(1:0}0"0)e.],&(#\|."{])|:
Not the shortest (my previous translation of dingledooper's was a couple bytes shorter), but I wanted to come up with a different approach:
(1:0}0"0)Is the matrix with all ones in the first row and zeros elsewhere...e.an elment of...],&(#\|."{])|:All possible rotations of the input, and all possible rotations of its transpose, catted together?
-
\$\begingroup\$ Fails with inputs like
1101 0010 0000 0000. \$\endgroup\$Bubbler– Bubbler2021年06月17日 04:35:13 +00:00Commented Jun 17, 2021 at 4:35 -
\$\begingroup\$ Ugh, nice catch. \$\endgroup\$Jonah– Jonah2021年06月17日 04:35:53 +00:00Commented Jun 17, 2021 at 4:35
-
\$\begingroup\$ @Bubbler Fixed. I really wanted to find a solution with using diagonal
/.sums, which produce a string of#ones and zero elsewhere iff valid input. But golfing that condition was cumbersome. Maybe you can make it work. \$\endgroup\$Jonah– Jonah2021年06月17日 05:00:28 +00:00Commented Jun 17, 2021 at 5:00 -
\$\begingroup\$ Why do you need to square element wise? The matrix always has 0 or 1 in it, and squaring either of those (or any product involving those) does nothing \$\endgroup\$2021年06月17日 13:56:57 +00:00Commented Jun 17, 2021 at 13:56
-
2\$\begingroup\$ Fails with
1100 1100 0000 0000– which suggests that it is the same algorithm as theorist's answer, that also fails with this case. :-) \$\endgroup\$xash– xash2021年06月17日 15:16:51 +00:00Commented Jun 17, 2021 at 15:16
Jelly, 9 bytes
,ZfJṁ=ⱮJƲ
Idea stolen from Razetime in TNB
, Pair the input with
Z its transpose.
f Filter the pair to elements contained in
Jṁ=ⱮJƲ every matrix of the same dimensions with a single column of 1s.
Jṁ Mold [1 .. len(input)] to the shape of the input.
ⱮJ For each 1 .. len(input),
= is each element equal to it?
Wolfram Language (Mathematica), 25 bytes
#||#/.{a_..}:>Tr@a==1&
Returns True if the matrix has a single line, and nonTrue otherwise.
#||# input OR its tranpose
/.{a_..}:> replace lists of repeated elements with
Tr@a==1 (is the sum of that element equal to 1?)
Then, any Or expression with True as an argument gets reduced to True.
-
3\$\begingroup\$ Can you add an explanation? I'm starting to learn Wolfram. \$\endgroup\$Jonah– Jonah2021年06月17日 05:38:12 +00:00Commented Jun 17, 2021 at 5:38
Python 2, 43 bytes
Heavily based on dingledooper's answer, which you should upvote.
lambda a,n:set(map(sum,a+zip(*a)))=={0,1,n}
Or:
Python 3, 44 bytes:
lambda a,n:{*map(sum,a+[*zip(*a)])}=={0,1,n}
Saves bytes with set unpacking, but loses bytes because zip doesn't return a list. Try it online!
Explanation
In a truthy input, the sum of a row or column must be one of these three numbers:
- \0ドル\$, if it is parallel to the line of \1ドル\$s
- \1ドル\$, if it is perpendicular to the line of \1ドル\$s
- \$n\$, if it is the line of \1ドル\$s
Any number other than these three indicates the existence of multiple lines or a partial line.
Furthermore, all three of these numbers must be represented among the list of sums:
- If \$n\$ is missing, there is no row or column that contains all \1ドル\$s.
- If \1ドル\$ is missing, there are multiple rows and columns containing \1ドル\$s.
- If \0ドル\$ is missing, the input has two perpendicular lines of \1ドル\$s (as in the second falsey test case). Conveniently, we don't have to worry about the case of a \1ドル \times 1\$ matrix, because we're given that \$n \geq 2\$.
Therefore:
set( ) # The set of
map(sum, ) # the sums of each
a+ # row and
zip(*a) # column
== # must be exactly
{0,1,n} # that set
Retina 0.8.2, 32 bytes
^(0*10*)(¶1円)*$|^(0+¶)*1+(¶0+)*$
Try it online! Turns out to be much like @Arnauld's answer, except I wanted to solve it for no trailing newline instead.
Vyxal, 14 bytes
:ÞTJv∑s2Nȯ1?"=
Another stealing of the python answer.
Explained
:ÞTJv∑s2Nȯ1?"=
:ÞTJ # merge the input list with itself transposed.
v∑s # sort the list that results from getting the sum of each item
2Nȯ # take the last two items of that list
1?"= # and check for equality with the list [1, second_input]
T-SQL, 152 bytes
Input is a table variable
Returns 1 for true, 0 for false
To save bytes, this can only handle matrix up to length 10
SELECT top 1iif(x=replace(a,0,'')or
sum(x)over()=x*2-1and a not like'%0%'and
0=min(a)over(),1,0)FROM(SELECT
rank()over(order by a)x,*FROM @)c ORDER BY-x
tinylisp, 88 bytes
(load library
(d _(q((M)(e 1(*(sum(map all M))(sum(map any M
(q((M)(+(_ M)(_(transpose M
The solution is the anonymous function in the last line. Try it online!
Here's an ungolfed version that verifies all test cases: Try it online!
Explanation
Define a helper function _ that takes a matrix (list of lists) M:
(sum(map all M)) Number of rows that are all 1s
(sum(map any M)) Number of rows that have any 1s
(* ) Multiply those two numbers
(e 1 ) Is the product equal to 1?
In other words, is there exactly one row that has all 1s, which is also the only row that has any 1s?
Then our main function needs only apply _ to the matrix and its transpose, and return truthy if either result is truthy:
(_ M) Test M
(_(transpose M)) Test transpose(M)
(+ ) Add the two results
Charcoal, 27 bytes
WS⊞υι∨∧=⌊υ⌈υ=1Σ⌈υ=ΦυΣι⟦⭆⌈υ1
Try it online! Link is to verbose version of code. Takes input as a newline-terminated list of strings. Explanation:
WS⊞υι
Input the matrix.
=⌊υ⌈υ All rows are identical
∧ Logical And
Σ⌈υ The sum of a row
=1 Equals literal `1`
∨ Logical Or
υ Input array
Φ Filtered where
ι Current row
Σ Is non-zero
= Equals
⭆⌈υ1 Row of 1s
⟦ As a 1-row 2D array
APL (Dyalog Unicode), (削除) 63 (削除ここまで) 55 bytes
{(F⍉⍵)+(F←{(1↑⍴⍵)=(+/,⍵)×ばつ+/∧/⍵})⍵}
- changed approach
- F used on input + input transposed
×ばつ+/∧/⍵ ⍝ number of all 1s lines multiplied by (+/,⍵) ⍝ total 1s (1↑⍴⍵)= ⍝ equal to side length?
PowerShell, (削除) 49 (削除ここまで) (削除) 45 (削除ここまで) 46 bytes
inspired by Arnauld's and Neil's answers.
+1 bytes with additional Test cases.
"$args "-match'^(0*10* )1円+$|^(0+ )*1+ [0 ]*$'
- convert the arguments to a string with space char as separator
- add the trail space char
- match with regexp
GNU-APL, 34 bytes
{+/(⍺≡+/,⍵)∧(⍵∧.=⍺⍴1)∨((⍺⍴1)∧.=⍵)}
Input the size of the matrix, and the matrix itself.
⍵∧.=⍺⍴1 finds the row with all ones, a1=1∧a2=1∧a3=1 ...
(⍺⍴1)∧.=⍵ finds the column with all ones
The disjunction of the above two ensures atleast one of them happends
⍺≡+/,⍵ ensures that only required numbers of ones are present
C (gcc), (削除) 121 (削除ここまで) 119 bytes
-2 bytes thanks to ceilingcat
l;e;r;o;a;f(m,n)int*m;{r=l=o=0;for(e=a=~0;r++<n;o|=*m,a&=*m++)~*m<<32-n?e&=!*m:++l;for(o-=a;a;a/=2)l+=a&1;r=l<2&&e^!o;}
This has entire rows stored in integer arrays, making the maximum matrix size 32.
Explore related questions
See similar questions with these tags.