46
\$\begingroup\$

A string is considered to be square if the following conditions are met:

  • Each line has the same number of characters
  • The number of characters on each line is equal to the number of lines.

Your task is to write a program or function which determines whether or not a given input string is a square.

You may require input to be delimited by your choice of LF, CR, or CRLF.

The newline character(s) are not considered part of the line's length.

You may require there to be or to not be a trailing newline in input, which doesn't count as an additional line.

Input is a string or 1D char array; it is not a list of strings.

You may assume input is non-empty and only contains printable ASCII, including spaces.

You must output a truthy value for square strings and a falsy one for other strings.

Truthy test cases:

foo
bar
baz
.
.s.
.ss
.s.
(s represents space)
ss
ss
(s represents space)
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa

Falsy test cases:

..
.
.


.
....


....
4444
333
22
333
333
abc.def.ghi

Note extra blank lines in some of the falsy cases.

This is - fewest bytes wins!

\$\endgroup\$
7
  • \$\begingroup\$ Possible duplicate of Language Design: 2-D Pattern Matching. Problem #5 is the same as this question. \$\endgroup\$ – mbomb007 Jun 6 '17 at 21:40
  • 1
    \$\begingroup\$ @mbomb007 I feel like the different winning criteria make this not a duplicate? "Golfiness" was one of the voting criteria but I don't think answers to that question will largely reflect on the ones here. \$\endgroup\$ – FryAmTheEggman Jun 6 '17 at 22:12
  • 3
    \$\begingroup\$ @mbomb007 I'm voting to leave this question open because, while it is a subset of the other question, the other question is restricted to languages created specifically for that question. \$\endgroup\$ – ETHproductions Jun 6 '17 at 22:15
  • 2
    \$\begingroup\$ @mbomb007: That's not a duplicate, because that question asks you to design a language for the purpose of answering the question, rather than answering in an existing language. Very few of the answers here would be legal there. \$\endgroup\$ – user62131 Jun 6 '17 at 22:29
  • 1
    \$\begingroup\$ @mbomb007: That's no reason to close this challenge, and give people nowhere to post their answers in pre-existing languages, though. It might potentially be an argument for closing the other challenge (because it's just a more restrictive version of this one), although I'd consider it a poor argument and believe both should be left open. \$\endgroup\$ – user62131 Jun 7 '17 at 17:47

51 Answers 51

1
2
1
\$\begingroup\$

APL (Dyalog), 17 bytes

Requires ⎕ML←3 which is default on many systems. Uses CR.

↓∘⎕FMT≡⎕TC[2]∘≠⊂⊢

Try it online!

↓∘⎕FMT [is the] split-into-lines Formatted-into-a-square argument

 identical to

⎕TC[2]∘≠ the into-groups-of-non-newline*-characters

 partitioned

 argument?

* the second element of the list of Terminal Control characters.


In version 16.0, one can write ↓∘⎕FMT≡⎕TC[3]∘≠⊆⊢ with ⎕ML←1.

\$\endgroup\$
2
  • \$\begingroup\$ Curious, what's ⎕ML? \$\endgroup\$ – Pavel Jun 6 '17 at 23:51
  • 1
    \$\begingroup\$ @Phoenix In Dyalog APL and APL+, Migration Level is a rough measure for the dialectical movement in direction of IBM's APL2. The higher the number, the more APL2-like does the language become. People migrating from APL2 to other APLs tend to run with a high ⎕ML, while people who started with the other APLs tend to run with a low ⎕ML. \$\endgroup\$ – Adám Jun 6 '17 at 23:55
1
\$\begingroup\$

PowerShell, 64 bytes

The same (split, line lengths, number of lines) approach as other non-golf language answers, but there's no nice map() equivalent, so it's an array of line lengths with the number of lines tagged onto the end, then that array is grouped. Squares come out like 3,3,3,3 -> 1 group, all line lengths and line count were equal and non-squares come out like 3,2,1 -> 3 groups, something was unequal in the square:

$f={@(@(($L="$args"-split"`n")|% le*)+$L.Count|group).Count-eq1}

Requires newline Linux-style endings, no trailing newline. e.g.

$Ttests = @(@'
foo
bar
baz
'@,
'.',
@'
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
'@
)
$Ttests = $Ttests | foreach {$_ -replace "`r"}

$Ttests | % { & $f $_ }

(And you can do similar for the false tests, but I won't put it here as there's more of them). The couple of @ symbols are required for when the input is the single '.' otherwise splitting it doesn't make an array of one string it just makes one string, and then the array concatenation doesn't output 1,1 it outputs 2.

I hoped it might be shorter to replace all the characters with 'a', and then brute force from 1 to Input Length all the squares 'a' and see if any matched the input. Once I got past param() and .Length and -join and -replace it ends up much longer at 81 bytes:

$f={param($s)!!(1..$s.Length|?{,('a'*$_)*$_-join"`n"-eq($s-replace"[^`n]",'a')})}
\$\endgroup\$
1
\$\begingroup\$

Grime, 11 bytes

e`.|_./+/.+

Prints 1 for squares and 0 for non-squares. Try it online!

Explanation

A detailed explanation can be found on the Grime tutorial page, which happens to contain this exact program as an example.

e`.|_./+/.+
e`            Match entire input against pattern:
  .           A single character
   |          OR
    _         a recursive match of this pattern
     ./+      with one column of characters on its right
        /     and below that
         .+   one row of characters.
\$\endgroup\$
1
\$\begingroup\$

Dart - 54 chars

q(s)=>!(s=s.split('\n')).any((x)=>x.length!=s.length);

(Expects input separated by newlines and not terminated by one)

Try it online

\$\endgroup\$
1
\$\begingroup\$

C#, 73 bytes

using System.Linq;s=>s.Split('\n').All(l=>l.Length==s.Split('\n').Length)

Explanation:

using System.Linq;    //Import Linq
s=>                   //Take input
s.Split('\n')         //Split the input stirng by line feeds
.All(l=>              //Make sure All lines in the array return true for:
l.Length              //The length of the line
==                    //Equaling
s.Split('\n').Length) //The length of the array split again by line feeds
\$\endgroup\$
1
\$\begingroup\$

MacOS Bash, 34

rs -EH|awk '{print $1}'|uniq|wc -l

rs is part of the default MacOS image. This will also work on Linux if rs is installed; it is on TIO.

  • rs -EH lists the length of each line, along with the number of lines
  • awk strips out extraneous info
  • uniq outputs one line if the line lengths and number of lines are all the same, but more otherwise
  • wc -l outputs 1 if the input is square or a greater number otherwise.

Try it online: Truthy, Falsey.

\$\endgroup\$
1
\$\begingroup\$

AWK, 49 bytes

{s=length($0)}L{x+=L!=s}{L=s}END{print x?0:L==NR}

Try it online!

Could also have used a BEGIN block to set FS="" but that would be the same byte-count. For some reason using the -F"" argument never seems to work.

\$\endgroup\$
1
\$\begingroup\$

Clojure, 42 chars

#(every?(fn[x](=(count %)x))(map count %))
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 20 bytes

A⁺№θ¶¹αF⪪θ¶A×α⁼αLιαα

Try it online! Prints - repeated by the side length as truthy, nothing as falsy.

\$\endgroup\$
1
\$\begingroup\$

><>, 76 bytes

This should work, next step is trying to golf it more!

0v      0   <
 >i:0)?!va=?^1+
:0)?v1n;\~l:   >
    >r:@=?!vr1-^
        ;n0<

Try it online! Or more more fun, try some examples using this animated interpreter.

printf "aaa\naas\naaa" | fish _square.fish --tick 0.1 --play

Explanation

The idea is roughly as follows.

  1. Fill the stack with the number of characters on each line.
  2. Push the length of the stack, corresponding to the number of lines (n).
  3. Do n times:
    • Check if bottom two elements are equal.
    • Remove deepest element.

Examples

For

aaa
aaa
aaa

we get [3, 3, 3, 3] after the first two steps and we can see that all three length 2 subsequences are equal. However, for

aaa
aa
a

we get [3, 2, 1, 3] and not all sequences are equal. For the last falsy case

`abc.def.ghi`

we get [11, 1] so there is only subpair we can check, but it is unequal so we return falsy.

\$\endgroup\$
1
\$\begingroup\$

Add++, 45 bytes

D,g,@,bU10C€=sVcG1+V10CAtbU€bLB]db=$bM*G=

Try it online!

How it works

Boy this was a long one (not even counting the footer)

D,g,@,		; Declare a monadic function 'g'
		; Example argument:    		 ['foo\nbar\nbaz']
	bU	; Unpack;		 STACK = ['f' 'o' 'o' '\n' 'b' 'a' 'r' '\n' 'b' 'a' 'z']
	10C€=s	; Count newlines;	 STACK = ['f' 'o' 'o' '\n' 'b' 'a' 'r' '\n' 'b' 'a' 'z' 2]
	VcG	; Keep last value;	 STACK = [2]
	1+V	; Increment and save;	 STACK = []			; STORE = 3
	10CAt	; Split arg on newlines; STACK = [['foo' 'bar' 'baz']]
	bU€bLB]	; Length of €ach;	 STACK = [[3 3 3]]
	db=	; Are they all equal?	 STACK = [[3 3 3] 1]
	$bM	; Max value;		 STACK = [1 3]
	*	; Logical AND;		 STACK = [3]
	G=	; Equals STORE?		 STACK = [1]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PHP, 65 bytes

while(~$c=$argv[1][$p++])$w+=":"^$c||$w=!$$w+=!!++$h;echo$$h==$h;

expects linux style line endings (\n) and a trailing newline; prints 1 for truthy, nothing for falsy.
Run with php -nr '<code>' '<input>' or try it online.


Btw: The naive approach takes 82 bytes:

<?=count($a=explode("
",$argv[1]))==min($m=array_map(strlen,$a))&min($m)==max($m);

expects linebreaks as on compile system and no trailing newline; prints 1 or 0.
Run with php -nR '<code>' '<input>'.

\$\endgroup\$
1
\$\begingroup\$

Python 3, 79 bytes

lambda a:len(set([len(list(i))for i in a.split('\n')]+[len(a.split('\n'))]))==1
\$\endgroup\$
1
\$\begingroup\$

Swift 3, 134 bytes

import Foundation;func r(s:String)->Bool{let i=s.components(separatedBy:"\n");return i.filter{$0.characters.count != i.count}.isEmpty}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Wren, 76 61 bytes

Fn.new{|a|a.split("\n").all{|x|x.count==a.split("\n").count}}

Try it online!

Old answer

The algorithm is essentially just copied from a 05AB1E answer.

Fn.new{|a|
var b=a.split("\n").map{|i|i.count}
return b.all{|i|i==b.count}
}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Red, 73 bytes

func[s][all collect[foreach b a: split s lf[keep(length? b)= length? a]]]

Try it online!

{abcd efg} represents true multiline string and not a list of strings, hence I need split s lf

\$\endgroup\$
1
\$\begingroup\$

SnakeEx, 38 bytes

h:{c<B>1}{c<L>1}{e<>}{e<R>}
c:.+$
e:.$

A match is truthy; no match is falsey. Try it here


The previous 50-byte SnakeEx submission was copied from the original solution to the detect-square-inputs problem in the 2D pattern-matching language challenge. Here's the thing: that problem says, "Match the entire input if it is a square block of characters." But for this problem, we merely need to match something if the input is a square block of characters. That enables us to use a different approach, saving bytes.

Instead of matching the whole square, we match its bottom row and rightmost column and assert that they are the same length. (It's important to pick the rightmost column, since that will fail if we have jagged input.)

  • c:.+$ Define c to match some number of characters and then the edge of the grid
  • e:.$ Define e to match the character it's currently on and then the edge of the grid
  • {c<B>1} Turn backwards (i.e. toward the left side), match c, and put that match in group 1
  • {c<L>1} Turn left (i.e. toward the top), match c, and put that match in group 1 (thereby requiring both matches to be the same length)
  • {e<>} Match e in the default direction (toward the right side)
  • {e<R>} Turn right (i.e. toward the bottom) and match e

The two c calls make sure the height and width are the same; the two e calls make sure our starting point is the bottom right corner.

\$\endgroup\$
1
\$\begingroup\$

Burlesque, 7 bytes

ln)L[sm

Try it online!

Requires a trailing newline after the input. Technically the trailing newline is only needed if the input ends on a newline (as ln ignores one trailing newline), and it doesn't make a difference whether it's there or not otherwise, but stating it as a blanket requirement is probably preferable. Returns 1 for square inputs and 0 otherwise.

Explanation:

ln       # Split input string into lines
  )      # Map each line...
   L[    # ...to its length
     sm  # Are all line lengths the same?
\$\endgroup\$
1
\$\begingroup\$

Google Sheets, 47

Closing parens/quotes already discounted.

Input: A1

A2 to A3:

=ArrayFormula(LEN(SPLIT(A1,"
")))
=A2=COUNTIF(2:2,A2)
\$\endgroup\$
0
\$\begingroup\$

SnakeEx, 50 bytes

This is BMac's solution to the problem for the 2D regex language design challenge.

m:{v<R>1}{h<>1}
v:${c<L>A1}+$
h:${c<R>A1}+$
c:$.+$

Try it online

\$\endgroup\$
0
\$\begingroup\$

J, 12 bytes

(*./=#)#;._2

Input requires trailing LF or CR.

Explanation:

  • ;._2 split into intervals and discard trailing atom
  • # count each group
  • (*./=#) is a fork which returns 0 (false) or 1 (true) if the LCM of the count of each group is equal to the count-of-counts

Tests

(*./=#)#;._2 'abc', LF, 'def', LF, 'ghi', LF   NB. 1 for well-formed input
(*./=#)#;._2 'abc', LF, 'def', LF, 'ghi'       NB. 0 because no trailing LF
\$\endgroup\$
6
  • \$\begingroup\$ How does it determine what the delimiter is..? And by the way, abc.def.ghi. should be falsy, so while clever, the delimiter trick is actually invalid. \$\endgroup\$ – Pavel Jun 8 '17 at 16:15
  • \$\begingroup\$ @Phoenix A test case to reflect that would be beneficial \$\endgroup\$ – Conor O'Brien Jun 9 '17 at 4:53
  • \$\begingroup\$ @Phoenix My answer used to just say "requires trailing delimiter" but I edited it to specifically call out either LF or CR. abc.def.ghi. would be truthy but abc.def.ghi.LF (trailing LF) would be falsy. \$\endgroup\$ – Alex Shroyer Jun 9 '17 at 19:28
  • \$\begingroup\$ abc.def.ghi. Is not a square string and should not be accepted. \$\endgroup\$ – Pavel Jun 9 '17 at 21:37
  • 1
    \$\begingroup\$ 15 Bytes for */(=#)#@>@cutLF, which only accepts LF as a delimiter, and does not require a trailing LF: */(=#)#@>@cutLF 'abc', LF, 'def', LF, 'ghi' returns 1 \$\endgroup\$ – Bolce Bussiere Mar 22 '18 at 17:53
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.