Suppose I have a string value str=xxx. Now I want to replace it via multi-index, such as {(1, 3):'rep1', (4, 7):'rep2', (8, 9):'rep3'}, without disturbing the index order. How can I do it?
Pseudo-code (in Python 2.7):
str = 'abcdefghij'
replacement = {(1, 3):'123', (4, 7):'+', (8, 9):'&'} # right index isn't include
# after some replacements:
str = some_replace(str, replacement)
# i want to get this:
print str
# 'a123d+h&j'
# since string is immutable, make a list out of the string to modify in-place
lst = list(str)
Use slice to modify items, a stronger explanation about slice and assignment can be found here; slice(*k) creates a slice object from the keys of the replacement. For instance, slice(*(1, 3)) gives a slice of slice(1, 3) which is equivalent to lst[1:3] when used as index, and replaces the corresponding elements with the corresponding value when the assignment on the slice is called:
# Here sort the index in reverse order so as to avoid tracking the index change due to the
# difference of the sizes between the index and replacement
for k, v in sorted(replacement.items(), reverse=True):
lst[slice(*k)] = v
''.join(lst)
# 'a123d+h&j'
Related
As of Python 3.7, dictionaries are guarantueed to keep insertion order. According to the original proposal for the change of memory layout (https://mail.python.org/pipermail/python-dev/2012-December/123028.html), an indices list stores the index of each value, indexed by the key hash. Therefore, it should be possible to efficiently retrieve an index of an item in the dictionary by its key. However, there seems to be no method for doing that. The only way I can think of is the following:
a = {}
a[1] = "b"
a[0] = "a"
a[2] = "c"
list(a).index(0) # returns 1
However, this is very inefficient. Do I have to use a library with a custom dictionary implementation or is there a way to access the internal CPython representation of a dictionary?
If you're going to perform this operation on the same dictionary multiple times (without changing its content), you could create an indexing dictionary for the keys and use that to get the index:
a = {1:"b", 0:"a", 2:"c"}
ia = {k:i for i,k in enumerate(a)}
print(ia[0]) # 1
If you don't want a separate dictionary, you could store the indexes along with the values in tuples:
a = {1:"b", 0:"a", 2:"c"}
a = {k:(i,v) for i,(k,v) in enumerate(a.items())}
print(a)
{1: (0, 'b'), 0: (1, 'a'), 2: (2, 'c')}
index,value = a[0]
print(index) # 1
Otherwise some form of sequential search will probably be your only option:
i = next(i for i,k in enumerate(a) if k=0)
How do i create a slice() object so that it would include the last element of a list/string
s = 'abcdef'
s[slice(2,4)]
works fine.
Say I wanted to get elements from second to the end, the equivalent of s[2:]
s[slice(2)] # only gives first two elements, argument is interpreted as the end of the range
s[slice(2,)] # same as above
s[slice(2, -1)] # gives a range from second to the end excluding the last element
s[slice(2, 0)] # gives empty as expected, since end of range before the start
I can get specifically the last element with slice(-1, -2, -1), this won't work correctly for more then one element.
If you want to include the last element you can do that in the following two ways :
s[slice(2,6)]
or replace 6 with len(s)
Or you could also do:
s[slice(2,None)]
You can test it with magic method __getitem__. The last object can be get with slice(-1, None, None):
s = 'abcdef'
class A:
def __getitem__(self, v):
print(v)
a = A()
a[-1:]
print("s[-1:] = ", s[-1:])
print("s[slice(-1, None, None)] = ", s[slice(-1, None, None)])
Prints:
slice(-1, None, None)
s[-1:] = f
s[slice(-1, None, None)] = f
Python sequence, including list object allows indexing. Any element in list can be accessed using zero based index. If index is a negative number, count of index starts from end. As we want last element in list, use -1 as index.
So you can just use:
s= "abcdef"
print(s[-1])
Result:
f
I'm having a hard time understanding why my function is not returning the reversed version of my list. I've spent a long time trying to understand why and i hit a wall: ---it only returns my list in ascending order.
letters = 'abcdefghijk'
numbers = '123456'
dict1 = {}
def reverseOrder(listing):
lst2 = []
lst2.append(listing)
lst2.sort(reverse=True)
return lst2
for l, n in zip(letters, numbers):
dict1.update({l:n})
lst1 = list(dict1) + list(dict1.values())
lst1.sort(key=reverseOrder)
print(lst1)
The key function passed to list.sort has a very specific purpose:
key specifies a function of one argument that is used to extract a comparison key from each list element (for example, key=str.lower). The key corresponding to each item in the list is calculated once and then used for the entire sorting process. The default value of None means that list items are sorted directly without calculating a separate key value.
So the function is supposed to take in a single list element, and then return a key that determines its sorting compared to the other elements.
For example, if you wanted to sort a list by the length of their contents, you could do it like this:
def lengthOfItem (item):
return len(item)
lst.sort(key=lengthOfItem)
Since the function only takes a single item, it makes it unsuitable for sorting behaviors where you actually need to compare two elements in order to make a relation. But those sortings are very inefficient, so you should avoid them.
In your case, it seems like you want to reverse your list. In that case you can just use list.reverse().
You are using sort function in an invalid way.
Here is the definition of sort function (from builtins.py):
def sort(self, key=None, reverse=False): # real signature unknown; restored from __doc__
""" L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE* """
pass
key argument has to be used if there is 'ambiguity' on how items have to be sorted e.g. items are tuples, dictionaries, etc.
Example:
lst = [(1, 2), (2, 1)]
lst.sort(key=lambda x: x[0]) # lst = [(1, 2), (2, 1)]
lst.sort(key=lambda x: x[1]) # lst = [(2, 1), (1, 2)]
Not quite sure what you want with this part though:
for l, n in zip(letters, numbers):
dict1.update({l:n})
lst1 = list(dict1) + list(dict1.values())
Seems like you want a list of all numbers and letters but you are doing it an odd way.
Edit: I have updated answer.
I want to make an array which contains arrays of pairs (C++ like pairs) of different sizes, any idea how to do it in python?
To be more specific, I need to know the equivalent to this C++ code in python:
vector<vector<pair<int, int>>> my_vector;
You can implement pairs with tuples, which can be created by separating elements with commas, usually with parenthesis enclosing them for better readability.
For the vectors, you can use lists which allow you to remove and add elements to them as you see fit. These are created with comma separated elements enclosed in square brackets.
An example of implementing your type of structure would be:
pair1 = (0, 1)
pair2 = (4, 3)
inner_vector1 = [pair1, pair2]
inner_vector2 = [pair2]
inner_vector2.append(pair1)
outer_vector = [inner_vector1, inner_vector2]
Which results in the object:
[[(0, 1), (4, 3)], [(4, 3), (0, 1)]]
Which can be visualized as:
outer_vector (list)
{
inner_vector1 (list)
{
pair1, (tuple)
pair2 (tuple)
},
inner_vector2 (list)
{
pair2, (tuple)
pair1 (tuple)
}
}
my_vector = [] # python list, for list of lists: use [[]]
my_vector.append([(3,5),(-2,1)]) # my_vector = [[(3,5),(-2,1)]]
my_vector.append([(8,4)]) # my_vector = [[(3,5),(-2,1)],[(8,4)]]
my_vector[1].append((-1,1)) # my_vector = [[(3,5),(-2,1)],[(8,4),(-1,1)]]
my_vector[0].pop() # my_vector = [[(3,5)],[(8,4),(-1,1)]]
my_vector.pop() # my_vector = [[(3,5)]]
append() is similar to push_back() method for C++ vector.
pop() is the same thing as pop() method for C++ vector.
() is used in place of make_pair() in C++ pair
Hope this clear it all.
In Python we call vector as list.
To construct a list, use
l = [].
To construct an empty list of list, use ll = [[]]
To construct an empty list of list of tuple, First, you need a list of list, uselll = [[]]. Then you construct a pair, in Python we call it tuple. Say we have a tuple t = (3, 9). Then we may append this tuple to our lll ==> Use lll[0].append(t).
Print out lll, we get [[(3, 9)]].
I have a long list that is made up of many tuples (over 100)that all contain 3 items that are strings
first_list = ('the','cat','went'),('back','too','scho'),('t/e','s/e/t','o/ve') etc
Many of the tuples are identically so i am using the set function to get out a unique set
Long_list = set(first_list)
i need the list in its original format , but i also need a duplicate list where the data has been cleaned
I need to remove all the "/" and Replace them with "#"
i can t seem to do this process. Initially i tried creating a foor loop to go through my list and then carry out the find and replace method.
The way i have done it gives me a new list that is made up of items , so the sets of tuples are not retained
for small_tuple in Long_list:
the_list = list(small_tuple)
for uncleaned_string in the_list:
time = uncleaned_string.replace('/','#')
last_list.append(time)
print last_list
Is there a way i can retain my original format of 3 items within tuple when i convert it back ?
tuple(myList) will convert myList into a tuple, provided that myList is something iterable like a list, a tuple, or a generator.
To convert a lists of lists in a list of tuples, using a list comprehension expression:
last_list = [tuple(x) for x in Long_list]
or, to also perform your string replacement:
last_list = [tuple(y.replace('/', '#') for y in x) for x in Long_list]
From Python's reference:
tuple( [iterable] )
Return a tuple whose items are the same and in the same order as iterable‘s items. iterable may be a sequence, a container that supports iteration, or an iterator object. If iterable is already a tuple, it is returned unchanged. For instance, tuple('abc') returns ('a', 'b', 'c') and tuple([1, 2, 3]) returns (1, 2, 3). If no argument is given, returns a new empty tuple, ().
tuple is an immutable sequence type, as documented in Sequence Types — str, unicode, list, tuple, bytearray, buffer, xrange. For other containers see the built in dict, list and [set] classes, and the collections module.
You could do something like the following using a list comprehension converted into a tuple:
for small_tuple in Long_list:
the_list = list(small_tuple)
last_list.append(tuple([uncleaned_string.replace('/','#') for uncleaned_string in the_list]))
print last_list
last_list = [tuple(s.replace('/', '#') for s in t) for t in Long_list]
Modified your code to fit your need
for small_tuple in Long_list:
the_list = list(small_tuple)
res=[]
for uncleaned_string in the_list:
time = uncleaned_string.replace('/','#')
res.append(time)
last_list.append(tuple(res))
print last_list
You can use an OrderedDict to remove the duplicates while preserving the order.
from collections import OrderedDict
x = OrderedDict.fromkeys(first_list)
Long_list = list(x)
Long_list contains unique tuples with order same as of first_list.