python order of elements in set - python

I do not understand the ordering what Python applies from holding sets. For example:
visited = set()
visited.add('C')
visited.add('A')
visited.add('B')
print(set)
The ordering is 'A', 'C', 'B'. Why 'A' is before 'C' (maybe alphabetical order)?
What I have to do in order to preserve the adding ordering, i.e. 'C', 'A', 'B'?

You cannot have order in sets. and there is no way to tell how Python orders it. Check this answer for alternatives.

Sets are different than lists. If you want to preserve an order, use a list.
For example :
a = []
a.append('C')
a.append('A')
a.append('B')
print a # ['C', 'A', 'B']

Related

Rearrange a list of strings

I want to rearrange or modify he sequence of elements (strings) in a list. This is the original list
['A', 'B', 'C', 'D', 'E', 'F', 'G']
I want to move E and F behind (or after?) B.
['A', 'B', 'E', 'F', 'C', 'D', 'G']
^^^ ^^^
The decision what to move comes from the user. There is no rule behind and no way to formulate that in an algorithm. In other words the action move something behind something other is input from the user; e.g. the user mark two elements with her/his mouse and drag an drop it behind another element.
My code works and is able to do this. But I wonder if there is a more efficient and pythonic way to do this. Maybe I missed some of Python's nice in-build features.
#!/usr/bin/env python3
# input data
original = list('ABCDEFG')
# move "EF" behind "B" (this is user input)
to_move = 'EF'
behind = 'B'
# expected result
rearanged = list('ABEFCDG')
# index for insertion
idx_behind = original.index(behind)
# each element to move
for c in reversed(to_move): # "reverse!"
# remove from original position
original.remove(c)
# add to new position
original.insert(idx_behind + 1, c)
# True
print(original == rearanged)
You can assume
Elements in original are unique.
to_move always exist in original.
behind always exist in original.
The elements in to_move are always adjacent.
Other example of possible input:
Move ['B'] behind F
Move ['A', 'B'] behind C
This is not possible:
Move ['A', 'F'] behind D
Don't use .remove when the goal is to erase from a specific position; though you may know what is at that position, .remove a) will search for it again, and b) remove the first occurrence, which is not necessarily the one you had in mind.
Don't remove elements one at a time if you want to remove several consecutive elements; that's why slices exist, and why the del operator works the way that it does. Not only is it already harder to iterate when you can say what you want directly, but you have to watch out for the usual problems with modifying a list while iterating over it.
Don't add elements one at a time if you want to add several elements that will be consecutive; instead, insert them all at once by slice assignment. Same reasons apply here.
Especially don't try to interleave insertion and removal operations. That's far more complex than necessary, and could cause problems if the insertion location overlaps the source location.
Thus:
original = list('ABCDEFG')
start = original.index('E')
# grabbing two consecutive elements:
to_move = original[start:start+2]
# removing them:
del original[start:start+2]
# now figure out where to insert in that result:
insertion_point = original.index('B') + 1
# and insert:
original[insertion_point:insertion_point] = to_move
If it is just a small number of items you want to rearrange, just swap the relevant elements:
lst = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
lst[2], lst[4] = lst[4], lst[2] # switch 'C' and 'E'
lst[3], lst[5] = lst[5], lst[3] # switch 'D' and 'F'
lst
['A', 'B', 'E', 'F', 'C', 'D', 'G']

What does a list sort(key=str.lower) do?

Can you explain the second line with explain?
spam = ['a', 'z', 'A', 'Z']
spam.sort(key=str.lower)
print(spam)
spam is a list, and lists in python have a built-in sort function that changes the list order from low to high values.
e.g.
Nums = [2,1,3]
Nums.sort()
Nums
Output
[1,2,3]
The key parameter of sort is a function that is applied to each element of the list before comparison in the sorting algorithm. str.lower is a function that returns characters in lowercase.
e.g.
A -> a
So, the second line sorts spam by the lowercase values of its elements.
Which should result in
[a,A,z,Z]
spam.sort(key=str.lower)
is sorting your spam list alphabetically as it's case-insensitive. So if you change your 3rd line to
print(spam)
you get
['a', 'A', 'z', 'Z']
without the key in your sort the sorted list would be
['A', 'Z', 'a', 'z']
spam.sort(key=str.lower)
sort() is a default function for sorting in python and it can take some sorting function as a parameter.
here key = str.lower is the sorting function which means that it should parse every string to lower case before sorting.
which means that this is case in sensitive search.
It performs case insensitive sorting.
Let's modify your example a bit, to include another entry "a":
spam = ['a', 'z', 'A', 'Z','a']
Naturally, you'd expect first "a" and second "a" to occur together. But they don't when you give key=str.lower, because of the properties of string ordering. Instead, a plain list.sort call will give you:
spam = ['a', 'z', 'A', 'Z','a']
spam.sort()
print(spam)
output
['A', 'Z', 'a', 'a', 'z']
On the other hand, specifying str.lower gives you this:
spam = ['a', 'z', 'A', 'Z','a']
spam.sort(key=str.lower)
print(spam)
output:
['a', 'A', 'a', 'z', 'Z']
Here, the original list elements are sorted with respect to their lowercased equivalents.
Basically, when str.lower is done then the data in spam becomes 'a','z','a','z' due to which when sorting is done then both 'a' will come first and then 'z' ... but as the actual spam is not altered and only while sorting the data's case was changed so you get the output as 'a' 'A' 'z' 'Z' ..
same result you will get when you do key=str.upper.
I had never programming in Python, but what i see:
spam is array of strings
spam.sort = sorts array, key - is current value, you can do smth.
str.lower - means you will translate each string to lower case (L => l)
and last line means you returns that array (maybe...)

How can I join two lists A and B, minimizing duplicates while preserving the relative order of each of the lists A and B within the resulting list?

I have two sequences of strings A and B input as lists which may or may not have contiguous duplicates.
A = ['S','D','D','M','C','M']
B = ['D','D','S','C','C','M']
I want to merge them while minimizing contiguous duplicates while maintaining the order of each sequence A and B.
R = ['D','S','D','S','D','C','D','M','C','M','C','M']
I want to find a dynamic programming approach to solve this problem but I am not sure where to begin or how to do it in python.
I'm not sure how your merging us supposed to work. I tried
[k for k, v in itertools.groupby(heapq.merge(A, B))]
But that gives me:
['D', 'S', 'D', 'M', 'C', 'M', 'S', 'C', 'M']

Python insert operation on list

I am newbie to Python and I have a doubt regarding insert operation on the list.
Example 1:
mylist = ['a','b','c','d','e']
mylist.insert(len(mylist),'f')
print(mylist)
Output:
['a', 'b', 'c', 'd', 'e', 'f']
Example 2:
mylist = ['a','b','c','d','e']
mylist.insert(10,'f')
print(mylist)
Output:
['a', 'b', 'c', 'd', 'e', 'f']
In second example why it still inserts 'f' element in the list even if I am giving index 10 to insert method?
The list.insert function will insert before the specified index. Since the list is not that long anyways in your example, it goes on the end. Why not just use list.append if you want to put stuff on the end anyways.
x = ['a']
x.append('b')
print x
Output is
['a', 'b']
The concept here is "insert before the element with this index". To be able to insert at the end, you have to allow the invalid off-the-end index. Since there are no well-defined "off-the-end iterators" or anything in Python, it makes more sense to just allow all indices than to allow one invalid one, but no others.

Combining elements in list using python

Given input:
list = [['a']['a', 'c']['d']]
Expected Ouput:
mylist = a,c,d
Tried various possible ways, but the error recieved is TypeError: list indices must be integers not tuple.
Tried:
1.
k= []
list = [['a']['a', 'c']['d']]
#k=str(list)
for item in list:
k+=item
print k
2.
print zip(*list)
etc.
Also to strip the opening and closing parenthesis.
What you want is flattening a list.
>>> import itertools
>>> l
[['a'], ['a', 'c'], ['d']]
>>> res = list(itertools.chain.from_iterable(l))
>>> res
['a', 'a', 'c', 'd']
>>> set(res) #for uniqify, but doesn't preserve order
{'a', 'c', 'd'}
Edit: And your problem is, when defining a list, you should seperate values with a comma. So, not:
list = [['a']['a', 'c']['d']]
Use commas:
list = [['a'], ['a', 'c'], ['d']]
And also, using list as a variable is a bad idea, it conflicts with builtin list type.
And, if you want to use a for loop:
l = [['a'], ['a', 'c'], ['d']]
k = []
for sublist in l:
for item in sublist:
if item not in k: #if you want list to be unique.
k.append(item)
But using itertools.chain is better idea and more pythonic I think.
While utdemir's answer does the job efficiently, I think you should read this - start from "11.6. Recursion".
The first examples deals with a similar problem, so you'll see how to deal with these kinds of problems using the basic tools.

Categories

Resources