Johnathan Scott
Johnathan Scott

Reputation: 291

How to determine if a two dimensional list is "rectangular"

Right now I'm trying to get my program to take a two dimensional list as an input and return either true or false depending on whether or not it is "rectangular" (eg. [[2,3],[1,5],[6,9]] is rectangular whereas [[2,3],[1,8,6]] is not.) So far I've come up with this:

def rectangular(List):
    n = List
    for i in n:
        if len(i) != len(n[0]):
            return False
        elif len(i) == len(n[0]):
            i

I can't seem to figure out how to create a "true" case. Using the elif above I'm able to cycle through the list but if i were to add a return true portion it stops as soon as that is the case. Would a while loop work better in this case? All help is appreciated! Thanks.

Upvotes: 3

Views: 2767

Answers (3)

abarnert
abarnert

Reputation: 366103

If you get to the end without finding a false case, then you know it's true, right? There aren't any other possibilities.

So, you can just remove the elif entirely, and just add a return True at the end:

def rectangular(List):
    n = List
    for i in n:
        if len(i) != len(n[0]):
            return False
    return True

As a side note, your elif that has exactly the opposite condition as the if is better written as just else:. That way, there's no chance of you getting the opposite condition wrong, no need for your readers to figure out that it's the opposite, etc.

Also, there's no reason to take the argument as List, then bind the same value to n and use that. Why not just take n in the first place?

def rectangular(n):
    for i in n:
        if len(i) != len(n[0]):
            return False
    return True

You can make this more concise, and maybe more Pythonic, by replacing the for statement with a generator expression and the all function:

def rectangular(n):
    return all(len(i) == len(n[0]) for i in n)

But really, this isn't much different from what you already have. You should learn how this works, but if you don't understand it yet, there's no problem doing it the more verbose way.


If you want to get clever:

def rectangular(n):
    lengths = {len(i) for i in n}
    return len(lengths) == 1

We're making a set of all of the lengths. Sets don't have duplicates, so this is a set of all of the distinct lengths. If there's only 1 distinct length, that means all of the lengths are the same.

However, note that for an empty list, this will return False (because there are 0 lengths, not 1), while the other two will return True (because a condition is vacuously true for all values if there are no values to test). I'm not sure which one you want, but it should be relatively easy to figure out how to change whichever one you choose to do the opposite.

Upvotes: 4

ssm
ssm

Reputation: 5383

You can make sure that the lengths of all elements of the list are the same length. Or in Python:

all(map(lambda m: len(m) == len(x[0]), x))

Where x is what you want to check.

The only problem with this solution is that the if the list looks like [ [1,2], [1,[1,2]], 'ab' ], it is still going to return True. So you additionally need to do some type checking.

Upvotes: 1

SethMMorton
SethMMorton

Reputation: 48835

Try using the all function with a generator:

def rectangular(lst):
    first_len = len(lst[0])
    # I used lst[1:] to skip the 0th element
    return all(len(x) == first_len for x in lst[1:])

The all function returns True if all elements of an iterable are True, and False otherwise.

It's good that you didn't call your variable list, but capitalized names usually represent a class in Python, so lst is a better choice than List.


NOTE: I made the assumption that "rectangular" means each sublist is the same length. If in reality each sublist should be (say) 2 elements long, just replace first_len with the literal 2 and remove the [1:] on lst[1:]. You may also want to add some exception handling in case you pass a list with only one element.

Upvotes: 4

Related Questions