Reputation: 2839
I don't know how to give an accurate title, but here's the problem.
The problem:
I want to give a ranking list (imagine some top list) with some position preserved already.
Say I got 7 slots [1, 2, 3, 4, 5, 6, 7, 8]
and some has already preserved postion 1, 3, 4, 7, 9. (As we only have 8 slots, the perserved postion 9 will means the last slot.)
Then I have 2, 5, 6 slots left, which I have to fill them with other objects.
The simplified question:
I have two list:
>>> a = [1, 3, 4, 7, 9]
>>> b = [object_x, object_y, object_z]
And I want to merge them to this:
>>> c = [1, object_x, 3, 4, object_y, object_z, 7, 9]
(We can take the 'object_x' here as 0.)
That's it, just want to see if there is an elegant way to implement this.
(Edit whole question based on the comments. Thank you guys very much.)
Upvotes: 1
Views: 145
Reputation: 35059
You would possibly be better off avoiding having to do this merging in the first place. If you know in advance how many possible ranks there are, you can start your list off as containing that many None
s, and every time you occupy a space,set that using list item assignment rather than appending. Then your final merge is as simple as:
def merge(a, b):
b = iter(b)
for i,x in a:
if x is None:
a[i] = next(b)
If you were so inclined, you could put this whoe data structure into a class, which would also allow you to, for example, check when you're trying to overwrite an occupied position (if that would be an error):
class Ranks:
def __init__(self, size):
self._list = [None] * size
def __getitem__(self, position):
return self._list[position]
def __setitem__(self, position, val):
if self._list[position] is None:
raise ValueError('attempting to clobber existing rank data')
self._list[position] = val
Upvotes: 0
Reputation: 2839
Thanks all, and I get this solution inspired by @jurgenreza
>>> a = [1, 3, 4, 7, 9]
>>> b = [0, 0, 0]
>>> for i in a:
b.insert(i - 1, i)
>>> print b
[1, 0, 3, 4, 0, 0, 7, 9]
Upvotes: 0
Reputation: 6086
This should also work:
>>>a = [2, 3, 5, 6, 7, 9]
>>>b = [0, 0, 0]
>>>length = len(a)
>>>i = 0
>>>while (i < length):
if a[i] != i+1:
a.insert(i, b.pop(0))
length += 1
i += 1
>>>print(a)
[0, 2, 3, 0, 5, 6, 7, 0, 9]
Upvotes: 0
Reputation: 88977
I believe this covers the edge cases, I do, however, agree with others that it seems there must be a better way of doing this. It might be worth explaining the context of what you are trying to do. There is probably a way to do it without all of this.
def merge(a, b):
b = list(b)
a = iter(a)
current = 1
for item in a:
while item != current:
if b:
yield b.pop(0)
else:
yield item
yield from a # <3.3 use `for item in a: yield item` instead.
return
current += 1
yield item
current += 1
Which appears to work as per your spec:
>>> print(list(merge([1, 3, 4, 7, 9], [0, 0, 0])))
[1, 0, 3, 4, 0, 0, 7, 9]
>>> print(list(merge([2, 4, 5], [1, 3])))
[1, 2, 3, 4, 5]
It's also unclear what should happen given extra elements in b
- this ignores them, but adding yield from b
(or, <3.3 for item in b: yield item
) to the end would give them as the final elements.
Upvotes: 1
Reputation: 298056
You could use a generator:
def merge(a, b):
b_clone = b[:]
for n in range(min(a), max(a) + 1):
if n in a:
yield n
elif b_clone:
yield b_clone.pop(0)
Upvotes: 2