1

I'm working through Automate the Boring Stuff with Python and have found a project I can seem to crack. It's pretty printing a lists of lists so they are all right justified, so you have to find the longest string length in the given lists of lists. I have tried to concat the lists of list together into one list, then find the max len value from that, and sub that into a for loop to print every string justified to that length, but it doesnt seem to be working. My code isn't taking the max length of all of the string values. I think it's only taking the max length from the first list because it says the max length is 7 (from 'oranges' i assume), when it should be 8 (from 'cherries'). My only guess is that is has something to do with itertools, and that itertools.chain doesnt instantly concat the list of lists in one action, but instead iterates through them as a list, so the first iteration took the first list, and longWord function took the max of only that first list instead of the entire concated new list. Any idea how I can fix this code to make it work properly?

Also, is there an easier way to concat lists, for example in Haskell, there is just a concat function to concat any given set of list of lists. Is there anything shorter than the itertools.chain.from_iterable thing?

import itertools

def printTable(table):
    newlist = list(itertools.chain.from_iterable(tableData))
    longWord = len(max(newlist))

    for i in range(len(table[0])):
        for j in range(len(table)):
            print ((table[j][i]).rjust(longWord), end = " ")
        print ("\n")
    print (newlist)
    print (str(longWord))
    print (max(newlist))



tableData = [['apples', 'oranges', 'cherries', 'banana'],
             ['Alice', 'Bob', 'Carol', 'David'],
             ['dogs', 'cats', 'moose', 'goose']]
  • as I remeber this problem you don't need `itertools` - you have to find the longest word for every column separately - so you will have 3 values, not one. – furas Dec 24 '16 at 06:16
  • Can you edit your question to include the result you're getting, and perhaps also the result you're trying to get? – TigerhawkT3 Dec 24 '16 at 06:17
  • add link to `Automate the Boring Stuff` with text of project. – furas Dec 24 '16 at 06:18
  • 1
    `max(somelist)` does not return the longest string in a list of strings. it returns the 'largest' (lexicographically) element. – pvg Dec 24 '16 at 06:18
  • Like @pvg says, what you want is `max(newlist, key=lambda v: len(v))` – mVChr Dec 24 '16 at 06:21
  • How to flatten a list - http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python The other thing that would make your life easier is reading up on list comprehensions – pvg Dec 24 '16 at 06:24
  • 1
    @mVChr or shorter with `key=len` – furas Dec 24 '16 at 06:25
  • derp derp a herpa derp derp - me ... thanks @furas – mVChr Dec 24 '16 at 06:26

2 Answers2

0

When you use longWord = len(max(newlist)) it returns you the word of which first letter having highest ascii value thats why it is returning "oranges". To find max_length of string available in list use following code:

newlist = list(itertools.chain.from_iterable(tableData))
max_length,longest_element = max([(len(x),x) for x in newlist])

use max_length, longest_element according to your requirement.

P.Madhukar
  • 454
  • 3
  • 12
0

As others said using max will compare strings lexicographically, not by lenght. If you want that you need to add key=len:

print(max(["abc", "b", "cd"], key=len)) # ==> abc

Note that the "Pythonic" way to do what you want to do would probably be

longword = max(len(s)
               for L in lists
               for s in L)

even if I personally find this multi-comprehension syntax sort of "backward" and would prefer

longword = max(max(len(s) for s in L)
               for L in lists)

or even

longword = max(max(map(len, L))
               for L in lists)

(but watch out that most Pythonistas don't use map)

About concatenating lists you can use sum(lists, []). Note however that creating a single list just to find the longest word seems silly.

6502
  • 112,025
  • 15
  • 165
  • 265
  • variables names are typically lowercase in python. The nonstandard and unnecessary linebreaking also doesn't really make this any clearer. `max(["abc", "b", "cd"], key=len)` is perfectly "pythonic" as well, there is nothing particularly more pythonic about combining the call to max with the flattening comprehension. – pvg Dec 24 '16 at 15:44
  • @pvg: I use uppercase `L` because in many coding fonts the lowercase letter `l` is hard to distinguish from the number `1`. The problem with the double comprehension is that the ranges are in far-to-near order: it would be more logical to say `max(len(s) for s in L for L in lists)` (because names are explained more locally) but this Python feature wasn't designed that way. – 6502 Dec 24 '16 at 18:40
  • You don't really have to use `l` either (if anything, if you're aiming for clarity you'd rename `longword` to something that does not suggest it's a word). The comments on `pythonic` are still, I think, quite misleading as well. – pvg Dec 24 '16 at 19:04
  • pvg: `L` is a perfectly good name for a local variable IMO; if you don't like then don't use it. Apparently you probably also overestimate how much I care of what YOU think is Pythonic... please go check the **official** definition of "Pythonic". – 6502 Dec 24 '16 at 21:10
  • There is no 'official' definition of pythonic but you'd be hard pressed to find any to support your claim `max(iterable, key=len)` is somehow unpythonic. The var naming does have an official standard, see PEP 8 and http://stackoverflow.com/questions/159720/what-is-the-naming-convention-in-python-for-variable-and-function-names I'm writing this stuff to point out some inaccuracies in your answer - both to suggest you might fix it but more importantly, so it doesn't mislead others. What you or I care about is pretty secondary, although it's odd you're taking this as some personal affront. – pvg Dec 24 '16 at 21:24
  • @pvg: exactly... seems you're slowing coming to the point. In my answer I can say what is more or less pythonic given that the term implies a "for me": sorry but in MY post pythonic means what I mean, not what you mean. Incidentally `max(iterable, key=len)` is indeed very pythonic (for me) but the original poster has a nested list structure and that is not going to work (unless coupling it with that ugly chaining that is precisely where the question came from). Better than it is a clear nested comprehension but unfortunately it has the minor wart of requiring an apparently illogical order. – 6502 Dec 24 '16 at 23:33
  • It seems you are rapidly becoming more condescending so let's end at this point. "pythonic" does not mean what you imply nor does it mean 'everyone's personal idea'. There's plenty of ink spilled on it but since you agree it's largely opinion based (especially in your case), you should probably just remove the mention of it. I'd argue same goes for the nonstandard formatting and personal digressions into what you find intuitive (what help is that to any future reader?) but that's clearly a lost cause. – pvg Dec 24 '16 at 23:44