Determining the length of strings in a list

Michael Spencer mahs at telcopartners.com
Mon Mar 14 15:29:05 EST 2005


robin.siebler at palmsource.com wrote:
> I have a dictionary.  Each key contains a list.  I am using the
> contents of the list to build a portion of a command line.
> 
> However, before I can build the command line, I have to make sure that
> the command isn't too long.

Depending on how you join the list items, you may just be able to use join 
followed by stdlib textwrap to do this in one step (note I've wrapped this 
example at width 20 rather than 200 to make the resulting list easier to read):

  >>> source = ["some", "text", "fragments", "in", "a", "list"] * 10
  >>> import textwrap
  >>> textwrap.wrap(" ".join(source),20)
  ['some text fragments', 'in a list some text', 'fragments in a list', 'some 
text fragments', 'in a list some text', 'fragments in a list', 'some text 
fragments', 'in a list some text', 'fragments in a list', 'some text fragments', 
'in a list some text', 'fragments in a list', 'some text fragments', 'in a list 
some text', 'fragments in a list']

This works because the join separator is whitespace, which textwrap ignores.  If 
however, you need a non-whitespace separator, then textwrap can lead to ugly 
results with a leading or trailing separator:

  >>> textwrap.wrap(", ".join(source),20)
  ['some, fragments, of,', 'text, some,', 'fragments, of, text,', 'some, 
fragments, of,', 'text, some,', 'fragments, of, text,', 'some, fragments, of,', 
'text, some,', 'fragments, of, text,', 'some, fragments, of,', 'text, some,', 
'fragments, of, text,', 'some, fragments, of,', 'text, some,', 'fragments, of, 
text']

If you care about this, you may be able to tweak textwrap.TextWrapper to handle 
this, or you could use your own function, like:


def iterjoin(iterable, separator = " ", width = 70):
     """joins an iterable of strings into strings with width <= maxlen
     Not (yet) rejected for inclusion in itertools ;-)"""
     accumulator = []
     len_accumulator = 0
     len_sep = len(separator)
     for item in iterable:
         item = item.expandtabs()
         len_item = len(item)
         trial_len = len_accumulator + len_sep + len_item
         if trial_len > width:
             yield separator.join(accumulator)
             accumulator = [item]
             len_accumulator = len_item
         else:
             # continue to build the command
             accumulator.append(item)
             len_accumulator = trial_len
     if accumulator:
         yield separator.join(accumulator)


  >>> list(iterjoin(source, ", ", width = 20))
  ['some, fragments', 'of, text, some', 'fragments, of, text', 'some, fragments, 
of', 'text, some', 'fragments, of, text', 'some, fragments, of', 'text, some', 
'fragments, of, text', 'some, fragments, of', 'text, some', 'fragments, of, 
text', 'some, fragments, of', 'text, some', 'fragments, of, text']
  >>>

Now you can simply iterate over each list in your dictionary:

for k in d:
     for command in iterjoin(d[k], your_separator_here, width = 200)

HTH

Michael







More information about the Python-list mailing list