Вы можете перебором, используя random.shuffle () :
import random
def neighbouring(l):
"""Returns True if any 2 elements in l have the same last name."""
return any( last == l[idx+1][1] for idx,(_,last) in enumerate(l[:-1]) )
first_names = ['an','bn','ji','au','jo','ki','ko','bo','mi','li']
last_names = ['A','A','A','R','R','R','C','C','C','C']
# combine first and last name to name-tuples
names = list(zip(first_names,last_names))
print(names)
tries = 0
len_names = len(names)
# brute force: shuffle until neighbouring(names) == False
while neighbouring(names) and tries < len_names*100: # abort after 100*listlenght tries
random.shuffle(names)
tries += 1
print(names)
Вывод:
# before
[('an', 'A'), ('bn', 'A'), ('ji', 'A'), ('au', 'R'), ('jo', 'R'),
('ki', 'R'), ('ko', 'C'), ('bo', 'C'), ('mi', 'C'), ('li', 'C')]
# after
[('bn', 'A'), ('jo', 'R'), ('mi', 'C'), ('au', 'R'), ('ko', 'C'),
('ji', 'A'), ('li', 'C'), ('an', 'A'), ('ki', 'R'), ('bo', 'C')]
Чтобы вернуть основные списки:
first_names, last_names = zip(*names)
print(list(first_names))
print(list(last_names))
Вывод:
['ko', 'bn', 'ki', 'an', 'bo', 'jo', 'mi', 'ji', 'li', 'au']
['C', 'A', 'R', 'A', 'C', 'R', 'C', 'A', 'C', 'R']
Исправлено для бесконечного прогона с именами, которые не могут быть объединены по желанию:
tries = 0
max_tries = len(names) * 100
while neighbouring(names) and tries < max_tries:
random.shuffle(names)
tries += 1
if tries == max_tries:
print("Check the data - list might still have neighboring dupes after ",
tries, " shufflings")
else:
print("Used ",tries," out of ",max_tries," shufflings")
print(names)
first_names, last_names = zip(*names)
print(list(first_names))
print(list(last_names))