Skip to main content
Code Review

Return to Answer

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

Since @Graipher @Graipher gave good advices for assignment 2, I’m going to focus on assignment 1.

Since @Graipher gave good advices for assignment 2, I’m going to focus on assignment 1.

Since @Graipher gave good advices for assignment 2, I’m going to focus on assignment 1.

Source Link

Since @Graipher gave good advices for assignment 2, I’m going to focus on assignment 1.

You don't provide the details of the assignment, but reading at the comments and the code, we can conclude that you need to split a user-provided string into 3 equal pieces. Now what do you do when the length of said string is not divisible by 3? You pad with extra spaces.

First of, since you use slices, it's absolutely not necessary:

>>> 'test'[:10000]
'test'

Second, I find it way too unbalanced in case the length of the string is of the form \3ドル\times n+1\$: two of the slices are 2 characters longer than the third one, where you could have had only one of the slices being 1 character longer than the other ones. But I’ll get to it later.

Now it's time to write an efficient splitter function. Let's write it in a way that the provided string is divisible by the number of required chunks. But most importantly, let's write it that accept the number of chunks as parameters, and not relly on the caller to compute it. And don't forget to document it:

def split(sentence, num_chunks):
 """Split the given sentence into num_chunk pieces.
 If the length of the sentence is not exactly divisible by
 num_chunks, discard extra characters.
 """
 chunk_size = len(sentence) // num_chunks
 return [
 sentence[chunk_size * i:chunck_size * (i+1)]
 for i in range(num_chunks)
 ]

We can then use this function to perform the assignment:

def assigment1():
 """Ask the user a sentence and slice it in 3 equal parts.
 Print each part individually.
 """
 sentence = input('Enter a sentence: ')
 print('Original sentence:', sentence)
 for num, slice in enumerate(split(sentence, 3), 1):
 print('Slice #', num, ': ', slice, sep='')

You'll note that I used a for loop instead of 3 separate variables: it allows to easily change the number of chunks without changing the whole code. In fact, it would probably be better to let this number be a parameter of the function with a default value of 3:

def assigment1(num_chunks=3):
 """Ask the user a sentence and slice it in num_chunks equal parts.
 Print each part individually.
 """
 sentence = input('Enter a sentence: ')
 print('Original sentence:', sentence)
 for num, slice in enumerate(split(sentence, num_chunks), 1):
 print('Slice #', num, ': ', slice, sep='')

Lastly, we are going to take into account the extra letters in split instead of discarding them. As a first approximation, to bring back your behaviour, let me introduce divmod which, as its name suggest, returns both the result of the division and the remainder of said division:

def split(sentence, num_chunks):
 """Split the given sentence into num_chunk pieces.
 If the length of the sentence is not exactly divisible by
 num_chunks, the last slice will be shorter.
 """
 chunk_size, remainder = divmod(len(sentence), num_chunks)
 if remainder:
 chunk_size += 1
 return [
 sentence[chunk_size * i:chunck_size * (i+1)]
 for i in range(num_chunks)
 ]

And build upon that to balance things a bit, since splitting a 16-characters long sentence into 5 parts would yield 4 slices of length 4 and an empty slice. The key idea is to use slices of varying lengths. The first ones should be 1 character longer than the last ones. How many exactly? The remainder of the division of the length by the number of chunks is what we need:

size, remainder = divmod(len(sentence), num_chunks)
chunks_sizes = [size + 1] * remainder + [size] * (num_chunks - remainder)

Should get us started. To figure out what is in chunks_sizes, consider len(sentence) to be of the form \$\text{num_chunks}\times n + m\$. So chunks_sizes will be \$n+1\$, \$m\$ times followed by enough \$n\$ to have a list of size num_chunks.

But, since we are slicing from the previous offset for the given length, we need to accumulate the chunk sizes to know from which offset to start each time. We would then need to zip offsets and chunks sizes together to create our slices:

def split(sentence, num_chunks):
 """Split the given sentence into num_chunk pieces.
 If the length of the sentence is not exactly divisible by
 num_chunks, some slices will be 1 character shorter than
 the others.
 """
 size, remainder = divmod(len(sentence), num_chunks)
 chunks_sizes = [size + 1] * remainder + [size] * (num_chunks - remainder)
 offsets = [sum(chunks_size[:i]) for i in range(len(chuncks_sizes))]
 return [sentence[o:o+s] for o, s in zip(offsets, chunks_sizes)]

Computing offsets that way is not very efficient as it runs in \$O(n^2)\$ but I find it somewhat clearer than using itertools.accumulate and padding the results with the first offset of 0.

lang-py

AltStyle によって変換されたページ (->オリジナル) /