4
\$\begingroup\$

I tried to solve the Packet Assembler task posted at r/dailyprogrammer.

The Question is this:

When a message is transmitted over the internet, it is split into multiple packets, each packet is transferred individually, and the packets are reassembled into the original message by the receiver. Because the internet exists in the real world, and because the real world can be messy, packets do not always arrive in the order in which they are sent. For today's challenge, your program must collect packets from stdin, assemble them in the correct order, and print the completed messages to stdout.

The point of reading from stdin is to simulate incoming packets. For the purposes of this challenge, assume there is a potentially unlimited number of packets. Your program should not depend on knowing how many packets there are in total. Simply sorting the input in its entirety would technically work, but defeats the purpose of this exercise.

Input Format is this:

Each line of input represents a single packet. Each line will be formatted as X Y Z some_text, where X Y and Z are positive integer and some_text is an arbitrary string. X represents the message ID (ie which message this packet is a part of). Y represents the packet ID (ie the index of this packet in the message) (packets are zero-indexed, so the first packet in a message will have Y=0, the last packet in a message will have Y=Z-1). Z represents the total number of packets in the message.

Here is the Python3 solution I did

from re import split

def add_id(packets, p_id, len):
    packets[p_id] = {}
    packets[p_id]["len"] = len
    packets[p_id]["packets"] = {}

    return packets


def add_packet(packets, p_id, p_num, p_len, msg):
    if p_id not in packets.keys():
        packets = add_id(packets, p_id, p_len)

    if p_num > packets[p_id]["len"]:
        return packets

    packets[p_id]["packets"][p_num] = msg

    return packets


def main():
    packets = {}
    while True:
        try:
            recv = split(r'\s+', input())

            packets = add_packet(packets, int(recv[0]), int(recv[1]),
                                int(recv[2]), " ".join(recv[3:]))
        except EOFError:
            break

    for p_id in sorted(packets):
        for packet in range(packets[p_id]["len"]):
            print("%d %d %d %s" %(p_id, packet, packets[p_id]["len"], packets[p_id]["packets"][packet]))


if __name__ == '__main__':
    main()

Please rate this solution and suggest some improvements that can be made?

\$\endgroup\$
  • 3
    \$\begingroup\$ Rate this solution is rather subjective (reviewers don't rate code on this site), but you'll definitely receive feedback and improvements on any/all aspects of the code. \$\endgroup\$ – Mathieu Guindon Oct 13 '17 at 13:38
  • \$\begingroup\$ @Mat'sMug I mean just reviewing it. \$\endgroup\$ – Jøê Grèéñ Oct 19 '17 at 14:47
2
\$\begingroup\$

I think this code is very straightforward and easy to read. Good job!

Some nitpicks are,

You have a few PEP8 violations none all that concerning.

  1. Should add a second white line between imports and your functions
  2. Line too long, at your print statement
  3. Continuation line under-indented for visual indent
  4. printf style formatting is recommended against

Code suggestions

I would use a namedtuple instead of a dictionary, since it is much cleaner looking and easier to use. When to use a namedtuple!

Using the above suggestions and adhering PEP8 I get the following.

from re import split
from collections import namedtuple


def get_messages():
    Message = namedtuple('Message', 'idx num length message')
    messages = []

    while True:
        try:
            recv = split(r'\s+', input())
            messages.append(Message(recv[0], recv[1], recv[2], ' '.join(recv[3:])))
        except EOFError:
            return messages


def print_messages(messages):
    for message in messages:
        print("{}  {} {} {}"
            .format(message.idx, message.num, message.length, message.message))


def main():    
    messages = sorted(get_messages(), key=lambda x: (x.idx, x.num))
    print_messages(messages)


if __name__ == '__main__':
    main()
\$\endgroup\$
  • \$\begingroup\$ Thanks! TBH i am not too familiar with NamedTuples, that's why I don't use them! Thanks for PEP8s too! \$\endgroup\$ – Jøê Grèéñ Oct 19 '17 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.