-3

If someone knows how to phrase the question to make it clearer, feel free to edit it!

I have a list like this:

a = [["Adolf", "10"], ["Hermann", "20"], ["Heinrich", "30"]]

and I have an 'update' list like this:

b = [["Rudolf", "40"], ["Adolf", "50"]]

I want to be able to add new entries and overwrite identical entries in list a using list b:

c = magic(a, b)

The result should be as follows:

>>> print(c)
[["Adolf", "50"], ["Hermann", "20"], ["Heinrich", "30"], ["Rudolf", "40"]]

Is there a function like magic in existence? If not, how could it be written?


EDIT: Just to be clear, I am aware of the dictionary approach. For my purposes, I need to have duplicate entries, so dictionaries are not appropriate -- that's why I asked about lists. Before it is mentioned, there'll be protections for these special duplicate entries. For example, let's say "Heinrich" is one of these special types of entry that can have duplicates:

a = [['Adolf', '10'], ['Hermann', '20'], ['Heinrich', '30'], ['Heinrich', '15']]

Now, let's say I have the update list as the following:

b = [['Rudolf', '40'], ['Adolf', '50']]

Updating list a with list b should result in the following list:

>>> print(c)
[['Adolf', '50'], ['Hermann', '20'], ['Heinrich', '30'], ['Heinrich', '15'], ['Rudolf', '40']]

As you can see, there are intended duplicate entries. This is why a dictionary cannot be used directly.

d3pd
  • 7,935
  • 24
  • 76
  • 127
  • You're using the wrong data structure. This should be in a dictionary. – g.d.d.c Nov 18 '14 at 17:33
  • No, there's no magic function for this. But you can use `collections.Counter` for this. By the way is the order important? – Ashwini Chaudhary Nov 18 '14 at 17:33
  • Have *you tried* to figure out how it could be written? Have any ideas, even? Shouldn't it be `['Adolf', '60']`? And should they really be strings not numbers? – jonrsharpe Nov 18 '14 at 17:36
  • @[g.d.d.c](http://stackoverflow.com/users/351031/g-d-d-c) I'm aware of the dictionary approach to this. I need to use *duplicate* entries, so a dictionary doesn't work for my purposes. (Any entries being updated shall not be duplicate entries.) @[Ashwini Chaudhary](http://stackoverflow.com/users/846892/ashwini-chaudhary) Keeping the order is preferable, yes. – d3pd Nov 18 '14 at 17:38
  • 3
    What do you mean *"I need to have duplicate entries"*? In that case, where does `["Adolf", "10"]` go? Under what circumstances are duplicates allowed? What is the logic for merging? – jonrsharpe Nov 18 '14 at 17:41
  • Seconding jonrsharpe, the entire point of your `magic` function seems to be to prevent duplicates. Does everyone here misunderstand you? – furkle Nov 18 '14 at 17:47

4 Answers4

1

You should probably be using a dictionary for this. You're essentially mimicking its functionality anyway. If you have a dictionary a and dict b:

a = { "Adolf": "10", "Hermann": "20", "Heinrich": "30" }
b = { "Rudolf": "40", "Adolf": "50" }

then you can just do as follows:

a.update(b)

One line! Easy as pie. And that's as close as you're going to come to a built-in magic(), I think. But if you needed to do this with only lists, without ever using a dictionary (because I can't imagine why it'd be okay to use a dictionary as an intermediate step, but not store your data in one), you could do it as follows:

def magic(original, update):
    for i in range(len(update)):
        found_match = False

        for j in range(len(original)):
            # if there's a matching 'key' in an index of the original list
            if update[i][0] == original[j][0]:
                found_match = True
                original[j][1] = update[i][1]

        # if there's no entry to override, place a new entry in
        if not found_match:
            original.append(update[i])

Again, though, unless you've got some super weird use case, I can't imagine why this is preferable collections- or performance-wise over a dictionary.

furkle
  • 5,019
  • 1
  • 15
  • 24
  • Thank you very much for your help there. The dictionary approach is very clean, but I need to have duplicate entries, so the list approach is what I'll go for. Thanks again. – d3pd Nov 18 '14 at 19:19
1
  1. Convert a to a dictionary
  2. Call the update method on a with a dictionary full of b as the argument
  3. Get a list of the items in the updated version of a

Here's an example:

adict = dict(a)
adict.update(dict(b))
[list(item) for item in adict.iteritems()]
8one6
  • 13,078
  • 12
  • 62
  • 84
  • Thanks for your help. Your explanation is very clear. As it happens, I need duplicate entries, so a list approach is what I'm going for. – d3pd Nov 18 '14 at 19:20
1
>>> a = [["Adolf", "10"], ["Hermann", "20"], ["Heinrich", "30"]]
>>> b = [["Rudolf", "40"], ["Adolf", "50"]
>>> c = [list(i) for i in (dict(a+b).items())] # if b is update list then use (a+b), if you write (b+a) it will treat a as update list.
>>> c
[['Hermann', '20'], ['Rudolf', '40'], ['Adolf', '50'], ['Heinrich', '30']]
Irshad Bhat
  • 8,479
  • 1
  • 26
  • 36
  • Thanks for your help and for your very clear and efficient approach using dictionaries internally. As it happens, I need duplicate entries, so a list approach is what I'm going for. – d3pd Nov 18 '14 at 19:22
1

I recommend you using dictionary as they mentioned.

I assume you have given list a and b

def magic(a, b):
    d = dict(a)   # convert a to a dictionary
    d.update(b)   # value updates
    result = [ list(i) for i in d.iteritems() ]
    return result

The result is in the form you want

BigTailWolf
  • 1,028
  • 6
  • 17
  • Thanks for your help and for details on how to make the function using the dictionary approach. As it happens, I need duplicate entries, so a list approach is what I'm going for. – d3pd Nov 18 '14 at 19:21