The closest working code I can think of to your example is:
name = ["Michael", "Helen", "Mike", "Joe", "Michael"]
time = ["08:42:39", "08:39:56", "08:58:43", "09:04:03", "05:32:54"]
seen_names = []
norepeat_list = []
for i in range(len(name)):
if name[i] not in seen_names:
seen_names.append(name[i])
norepeat_list.append((name[i], time[i]))
for name_time in norepeat_list:
print(name_time)
but note that I've introduced an extra seen_names
array to keep track of things you've already seen. Having this extra list is bad for maintenance as you need to make sure both lists stay in sync with each other. It's also bad for performance as checking whether an item is in a list
takes time proportional to the length of the list, i.e. it gets slower for longer lists. It would be better to use a set
to track the items you've seen, as this wouldn't slow down as more items get added.
A more significant improvement would be to use a dictionary/dict
which allows you to associate arbitrary data (i.e. your times) with a set of items (i.e. your names). A naive translation of the above code would be:
names = ["Michael", "Helen", "Mike", "Joe", "Michael"]
times = ["08:42:39", "08:39:56", "08:58:43", "09:04:03", "05:32:54"]
names_and_times = {}
for i in range(len(names)):
if names[i] not in names_and_times:
names_and_times[names[i]] = times[i]
for name_time in names_and_times.items():
print(name_time)
Note that I've switched to a naming convention where plurals indicate a container of multiple values.
This could be improved by noticing that it repeats names[i]
a lot. An way to reduce this would be to use enumerate
:
names_and_times = {}
for i, name in enumerate(names):
if name not in names_and_times:
names_and_times[name] = times[i]
or alternatively, you could use zip
as many other answers have suggested:
names_and_times = {}
for name, time in zip(names, times):
if name not in names_and_times:
names_and_times[name] = time
another variant would be to exploit the fact that dictionaries can't have duplicates, so setting a dictionary item with the same item multiple times would just change the value rather than adding a new entry:
names_and_times = {}
for name, time in zip(names, times):
names_and_times[name] = time
Note that this leaves the last time set for each name rather than the first. Your question doesn't seem to express a preference, but this could be changed by iterating in reverse order:
names_and_times = {}
for name, time in zip(reversed(names), reversed(times)):
names_and_times[name] = time
Next we could use a dictionary comprehension, which cleans the above up to:
names_and_times = {
name: time
for name, time in zip(names, time)
}
Finally we get to my original comment about things being magical, which exploits this usage of zip
and the fact that passing an Iterable
of pairs causes the constructor of a dict
to build a dictionary where the first item of each pair is the key and the second item is the value:
names_and_times = dict(zip(names, times))
or if you want the first time
for each name
you could do:
names_and_times = dict(zip(reversed(names), reversed(times)))
All of my examples leave names_and_times
as a dictionary, but if you wanted to convert back to a list you can just do:
names_and_times = list(names_and_times.items())