Skip to content

Instantly share code, notes, and snippets.

@rmela
Last active April 26, 2021 09:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmela/0867e5c195c393605879de0dc094e17a to your computer and use it in GitHub Desktop.
Save rmela/0867e5c195c393605879de0dc094e17a to your computer and use it in GitHub Desktop.
merge python named tuples
#
# I was given about 10 minutes to figure out an exercise that
# boiled down to merging named tuples
#
# Weird thing to expect someone to know. Certainly anyone who knows this
# off the top of their head knows a lot about Python. But not everyone
# good developer will know this little corner of Python.
#
# It took me some time inspecting tuples to come up with this approach, slowed
# by my discomfort with relying on single-underscore members of library objects
#
# Needless to say I way overshot on time.
#
# The solution here seems kinda dicey - I don't like relying on
# single-underscore members of objects, but it works.
#
# Important to note that the parameters are positional.
# So for
#
# C = namedtuple( 'C', a._fields + b._fields )
#
# you probably wouldn't want the results of
#
# c = C( *b, *a )
#
# A twist to consider is the case where A and B both have a field
# of the same name.
#
from collections import namedtuple
A = namedtuple( 'A', ['a1', 'a2'] )
B = namedtuple( 'B', ['b1', 'b2'] )
C = namedtuple( 'C', A._fields + B._fields )
a = A( 'aaa1', 'aaa2' )
b = B( 'bbb1', 'bbb2' )
c = C( *a, *b )
print( c )
# => C(b1='aaa1', b2='aaa2', a1='bbb1', a2='bbb2')
#!/usr/bin/env python3
"""
Merge multiple objects into a single named tuple
"""
from collections import namedtuple
from functools import reduce
def reducer( accum, d ):
accum.update(d)
return accum
def tuplemerge( *dictionaries ):
merged = reduce( reducer, dictionaries, {} )
return namedtuple('Merged', merged )(**merged) # <==== Gist of the gist
if __name__ == '__main__':
obj1 = { 'a': 1, 'b': 2, 'c': 3 }
obj2 = { 'd': 44, 'e': 55, 'f': 66 }
obj3 = { 'g': 88, 'h': 99, 'f': 111 } # <=== this 'f' overrides previous 'f'
print(tuplemerge( obj1,obj2,obj3 ))
# => Merged(a=1, b=2, c=3, d=44, e=55, f=111, g=88, h=99)
@HaitaiNg
Copy link

HaitaiNg commented Aug 9, 2020

Thank you for this post. I was also asked this question during an interview, and I had a very similar experience. I also had a very limited amount of time (< 15 minutes) to develop a solution. I felt it was a language specific question, as this places a major emphasis on one's knowledge of python and python syntax

@bsridatta
Copy link

Same spot - really regret trying to play with namedtuples that I am not very familiar with. But I remember just converting them dicts. It took no more than couple of minutes to do this

from collections import namedtuple

A = namedtuple( 'A', ['a1', 'a2'] )
B = namedtuple( 'B', ['b1', 'b2'] )
C = namedtuple( 'C', ['a1', 'c2'] )

a = A( 'aa1', 'aa2' )
b = B( 'bb1', 'bb2' )
c = C( 'cc1', 'cc2' )

def merge(ntuples):
    m = {}
    for i in ntuples:
        m.update(i._asdict())
    M = namedtuple("M", m.keys())(*m.values())
    return M
    
print(merge([a,b,c]))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment