2
\$\begingroup\$

We have three integers:

A, B, C where the first (i.e. the most significant) digit of C is the first digit of A, the second digit of C is the first digit of B, the third digit of C is the second digit of A, the fourth digit of C is the second digit of B etc.

If one of the integers A and B runs out of digits, the remaining digits of the other integer are appended to the result.

Examples:

A = 1 5 4 8
B =  3 6 9    =>
C = 1356498

A = 1 0
B =  6 58    => 
C = 16058.

Here is my function which has two arguments, the integers A and B and returns the third integer C:

def myfunction(numberA, numberB):
    numberAstr = str(numberA)
    numberBstr = str(numberB)
    lenght1 = len(numberAstr)
    lenght2 = len(numberBstr)
    lenght3 = lenght1 + lenght2

    cl = []
    c = 0
    al = list(map(int, str(numberA)))
    bl = list(map(int, str(numberB)))

    if lenght1 >= lenght2:
        for i in range(lenght1):
            cl.append(al[i])
            if i <= (lenght2 - 1):
                cl.append(bl[i])
            print("Loop No:", i)
            print(cl)
    elif lenght2 > lenght1:
            for i in range(lenght2):
                if i <= (lenght1 - 1):
                    cl.append(al[i])
                cl.append(bl[i])
            print("Loop No:", i)
            print(cl)
    for i in range(lenght3):
        c += cl[i] * (10 ** (lenght3 - i))
    c //= 10
    return c

numberA = int(input("Enter the first number: "))
numberB = int(input("Enter the second number: "))
print('Integer C:', myfunction(numberA, numberB))

This function works just fine, but I'm sure that there is a pythonic way to do this! So I'm asking for any ideas to improve code efficiency.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Welcome to CodeReview! To be honest, I haven't quite understood the problem you are trying to solve, maybe an example would make things clearer ? \$\endgroup\$
    – SylvainD
    Feb 16 '16 at 20:45
  • \$\begingroup\$ So, am I right in thinking C is the result? I think (as @Josay pointed out, an example (or clearer explanation) of the problem would help. \$\endgroup\$ Feb 16 '16 at 21:21
  • \$\begingroup\$ Are you trying to interleave the digits of A and B to get C? \$\endgroup\$
    – Zack
    Feb 16 '16 at 22:27
2
\$\begingroup\$

You can use more built-in characteristics of the strings. This code grabs each pair of digits and builds a list, which it then joins with no separator. Then it adds the remainder from each string. The shorter string's remainder is the empty string.

def int_merge(a, b):
    str_a = str(a)
    str_b = str(b)
    min_len = min(len(str_a), len(str_b))

    # Grab pairs of numbers while the lengths of both strings allow.
    # After that, add the remainder -- the shorter string will have none.
    result = ''.join([str_a[i]+str_b[i] for i in range(min_len)]) + \
             str_a[min_len:] + str_b[min_len:]
    return result

test = [
    (1548, 369),
    (1356, 24),
    (13, 2456)
]
for case in test:
    print int_merge(case[0], case[1])
\$\endgroup\$
2
  • \$\begingroup\$ +1 for the testcases. You might want to also specify the expected result, though. test = [(1548, 369, 1356498), ...], and then use assert int_merge(case[0], case[1]) == case[2]. \$\endgroup\$ Feb 17 '16 at 8:51
  • 1
    \$\begingroup\$ Also, the code given is python-3.x (see use of input instead of raw_input), while your code is python-2.x. \$\endgroup\$ Feb 17 '16 at 8:52
0
\$\begingroup\$

I'm going to look at the code without the intermediate print statements. They expose an implementation detail, and not the end-result.

def myfunction(numberA, numberB):
    numberAstr = str(numberA)
    numberBstr = str(numberB)
    lenght1 = len(numberAstr)
    lenght2 = len(numberBstr)
    lenght3 = lenght1 + lenght2

    cl = []
    c = 0
    al = list(map(int, str(numberA)))
    bl = list(map(int, str(numberB)))

    if lenght1 >= lenght2:
        for i in range(lenght1):
            cl.append(al[i])
            if i <= (lenght2 - 1):
                cl.append(bl[i])
    elif lenght2 > lenght1:
            for i in range(lenght2):
                if i <= (lenght1 - 1):
                    cl.append(al[i])
                cl.append(bl[i])
    for i in range(lenght3):
        c += cl[i] * (10 ** (lenght3 - i))
    c //= 10
    return c

numberA = int(input("Enter the first number: "))
numberB = int(input("Enter the second number: "))
print('Integer C:', myfunction(numberA, numberB))

Your code is doing too much in the same place. First, it converts the numbers to lists of digits, merges them, and finally builds up an integer again. It would be good to separate this into multiple functions.

In pseudo-code:

def myfunction(numberA, numberB):
    numberAstr = str(numberA)
    numberBstr = str(numberB)
    result_string = merge(numberAstr, numberBstr)
    return string_to_int(result_string)

Let's fill in the gaps. First the merging part. You have a lot of conditionals. Consider what would happen if you'd have to handle 3 or 4 numbers instead of just 2. Let's write something a bit more generic, shall we?

def merge(iterableA, iterableB):
    merged = []
    iterators = [iter(iterableA), iter(iterableB)]
    while iterators:
        exhausted_iterators = set()
        for iterator in iterators:
            try:
                merged.append(next(iterator))
            except StopIteration:
                exhausted_iterators.add(iterator)

        # Remove iterators when they are exhausted. We need to do this in a
        # separate loop because we can not modify a list while iterating over
        # it.
        for exhausted_iterator in exhausted_iterators:
            iterators.remove(exhausted_iterator)
    return merged

Instead of for only 2 strings, this works for many. Well, not quite. But we can fix that easily.

def merge(*iterables):
    merged = []
    iterators = list(map(iter, iterables))
    ...

Let's see it in action.

>>> merge('hello', 'world', 'here', 'I', 'am')
['h', 'w', 'h', 'I', 'a', 'e', 'o', 'e', 'm', 'l', 'r', 'r', 'l', 'l', 'e', 'o', 'd']

Ok, so we do not get a string, but a list of characters. That's what ''.join() is for. Finally, we need to convert it back to an integer, we can do that using int(...).

def merge(*iterables):
    merged = []
    iterators = list(map(iter, iterables))
    while iterators:
        exhausted_iterators = set()
        for iterator in iterators:
            try:
                merged.append(next(iterator))
            except StopIteration:
                exhausted_iterators.add(iterator)

        # Remove iterators when they are exhausted. We need to do this in a
        # separate loop because we can not modify a list while iterating over
        # it.
        for exhausted_iterator in exhausted_iterators:
            iterators.remove(exhausted_iterator)
    return merged


def myfunction(numberA, numberB):
    numberAstr = str(numberA)
    numberBstr = str(numberB)
    result_digits = merge(numberAstr, numberBstr)
    return int(''.join(result_digits))


numberA = int(input("Enter the first number: "))
numberB = int(input("Enter the second number: "))
print('Integer C:', myfunction(numberA, numberB))

(One advice I personally have: When somebody ever asks you to do something for 2 items, try to keep in mind that they will later on think of asking you to do it for 3 items instead, because 'what is just one more'. Keep that in mind when writing algorithms. Sometimes you'll be worse off, but often replacing 2 with 'n with n >= 2' in your head gives you inspiration for better algorithms. Count "0", "1", "many".)

\$\endgroup\$

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.