0

I am aiming to do something similar to what might usually be done with something like textwrap.wrap, but instead of wrapping text with a specified maximum length I wish to instead specify how many lines.

I have split my string into an array of words at word barriers and now I want to rejoin my array of strings with a space such that I have a specified number of lines.

Here's what I have so far; num is the number of lines I require, words is an array of words. wpc is an (incorrect) assumption of how many "words per chunk":

num = 4
words = [
  "The",
  "quick",
  "brown",
  "fox",
  "jumps",
  "over",
  "the",
  "lazy",
  "dog"
]
wpc = math.ceil(len(words)/num)
chunks = [' '.join(words[num*i:num*(i+1)]) for i in range(wpc)]

This gives the incorrect result:

[
  "The quick brown fox",
  "jumps over the lazy",
  "dog"
]

Which has 3 lines not the 4 required.

Both the list of words and the number of lines required are dynamic, where am I going wrong?

The correct output is a bit dubious.. one possibility is

[
  "The quick brown",
  "fox jumps",
  "over the",
  "lazy dog"
]

But of course the "3 word" line could be anywhere. It doesn't matter too much how the odd line is placed (first, last, randomly) so long as there are always num lines.

Additionally if you added more words it would be good to evenly distribute the words (again, I'm not too fussed how they get distributed):

[
  "The quick brown",
  "giant fox jumps",
  "over the very",
  "lazy dog"
]
Jamiec
  • 133,658
  • 13
  • 134
  • 193

1 Answers1

2

You flipped the use of wpc and num, and the use of ceil is wrong here - I think.

Here's a solution:

import math

num = 4
words = [
  "The",
  "quick",
  "brown",
  "fox",
  "jumps",
  "over",
  "the",
  "lazy",
  "dog"
]
wpc = math.floor(len(words)/num)
chunks = [' '.join(words[wpc*i:wpc*(i+1)]) for i in range(num)]

chunks[-1] = " ".join([chunks[-1]] + words[wpc * num:])

The result is:

['The quick', 'brown fox', 'jumps over', 'the lazy dog']

An evenly distribute solution:

Thqt's slightly more complicated. Basically, I understand what's the minimal number of words per chunk (2 in this case), and randomly spread the extra words between some of the chunks.

num = 4
words = [
  "The",
  "quick",
  "brown",
  "fox",
  "jumps",
  "over",
  "the",
  "lazy",
  "dog", 
    "bla"
]

base_words_per_chunk = math.floor(len(words)/num)
extra_words = len(words) - num * base_words_per_chunk
words_per_chunk = [base_words_per_chunk] * num

larger_chunks = random.sample(range(num), extra_words)
for inx in larger_chunks:
    words_per_chunk[inx] = words_per_chunk[inx] + 1

start_point = 0
chunks = []
for inx in itertools.accumulate(words_per_chunk):
    chunk = words[start_point:inx]
    chunks.append(chunk)
    start_point = inx
Roy2012
  • 11,755
  • 2
  • 22
  • 35