List sorting in python combine with string - sorting

I have a string that goes like this
string = "CCB"
and a list
list = ['C','C','B','CC']
How do i sort them by their appearance order in the string (high priority) and their length(lower priority). After sorted the list should be like this
list = ['C' , 'C ', 'CC' , 'B']
I'm having some problem with this. does anyone have a python function or how to implement this problem?

One method is to create tuples of the indices and length before sorting, then reducing to the original input after. Below is one such example of doing this. Note that if the index is not found, we assume that it should come at the end and then just be sorted by length.
def sortby_index_length(input, items):
def index_or_large(haystack, needle):
try:
return haystack.index(needle)
except ValueError:
return len(haystack)
indexes = list(map(lambda x: (x, index_or_large(input, x)), items))
indexes.sort(key=lambda xy: (xy[1], len(xy[0])))
return list(map(lambda x: x[0], indexes))
print(sortby_index_length("CCB", ['C','C','B','CC']))
Which gives the expected output of ['C', 'C', 'CC', 'B']. This also uses the sort function where we specify the sorting ordering to be index tie broken by length.

Related

generating powerset with backtracking where subsets with lower number of elements appear earlier and they are sorted

I was solving the classic powerset generation using backtracking. Now, let's say, I add another constraint, the output should appear in a specific order.
For input = [1, 2, 3], the output should be [[], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]]
My general solution (which generates the superset but not in any specific order):
class Solution:
def build_subsets(self, cur_i = 0, cur_ls = []):
if cur_i == len(self.nums):
self.output.append(cur_ls)
return # this is mendatory
self.build_subsets(cur_i + 1, cur_ls)
self.build_subsets(cur_i + 1, cur_ls + [self.nums[cur_i]])
def subsets(self, nums):
self.nums = nums
self.output = []
self.build_subsets()
return self.output
How can I change my backtracking code to find the output in the specific order (subsets with a lower number of elements appear earlier and they are sorted [for a group of a fixed number of elements])?
Update:
The following code which uses combinations function satisfy the condition. Now, the question becomes how can I write combinations using backtracking as I want to understand the recursive process for generating such a list.
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
Your code has almost everything you need to generate the subsets in the desired order. The key missing piece is the for loop that determines the length of the subsets, as seen in the code that uses combinations. That loop starts by generating the subsets of length 0. It then continues with successively larger subsets until it reaches the final subset that includes all of the numbers.
So you need to add a similar for loop to the subsets function, and the desired length needs to be passed to the build_subsets function. The build_subsets function then needs to terminate the recursion when the subset reaches the desired length.
Other changes that are needed are:
The order of the recursive calls needs to be reversed so that the current number is used, before being skipped.
When the current number is skipped, it's necessary to verify that enough numbers remain to complete the subset, before making the recursive call.
With those changes, the code looks like this:
class Solution:
def build_subsets(self, desired_length, cur_i = 0, cur_ls = []):
# if the current subset is the desired length, add it to the output
if len(cur_ls) == desired_length:
self.output.append(cur_ls)
return
# use the current number
self.build_subsets(desired_length, cur_i+1, cur_ls + [self.nums[cur_i]]);
# skip the current number, if there are enough numbers to finish the subset
cur_i += 1
if len(self.nums) - cur_i >= desired_length - len(cur_ls):
self.build_subsets(desired_length, cur_i, cur_ls);
def subsets(self, nums):
self.nums = nums
self.output = []
for desired_length in range(len(nums)+1):
self.build_subsets(desired_length)
return self.output
the big picture
This solution hopes to teach you that complex problems can be made by combining solutions to smaller sub-problems. After all, this is often the way we should be thinking about recursive problems. Recursion is a functional heritage and so using it with functional style will yield the best results. This means avoiding things like mutation, variable reassignment, and other side effects.
def powerset(t):
for k in range(len(t)):
yield from combinations(t, k)
yield t
for x in powerset((1,2,3)):
print(x)
The combinations will be ordered in the same way the original input is ordered. If you would like the output to be sorted, simply sort the input first -
()
(1,)
(2,)
(3,)
(1, 2)
(1, 3)
(2, 3)
(1, 2, 3)
Since you asked how to write it, here is combinations as its own generic function -
def combinations(t, k):
if k <= 0:
yield ()
elif not t:
return
else:
for x in combinations(t[1:], k - 1):
yield (t[0], *x)
yield from combinations(t[1:], k)
itertools
Or you can use the built in itertools.combinations function, provided by python -
from itertools import combinations # <- import
def powerset(t):
for k in range(len(t)):
yield from combinations(t, k) # <- provided by python
yield t
for x in powerset((3,2,1)): # <- let's try a different input order
print(x)
()
(3,)
(2,)
(1,)
(3, 2)
(3, 1)
(2, 1)
(3, 2, 1)
accept list as input
Notice above there's no need to "generate" the final subset as it is simply t itself. If you want to accept a list or non-tuple as an input, we can slightly alter powerset -
def powerset(t):
for k in range(len(t)):
yield from combinations(t, k)
yield tuple(t) # <- coerce tuple
for x in powerset([9,3,6]): # <- list input
print(x)
Before this change the program would output [9,3,6] instead of the desired (9,3,6) -
()
(9,)
(3,)
(6,)
(9, 3)
(9, 6)
(3, 6)
(9, 3, 6)
generators
Notice we use yield to lazily generate the possible subsets. Generators are a good fit for combinatorics problems because often times we do not need to iterate the entire solution space before an answer can be determined. This way the caller can work with the results ad hoc, as they are generated, without necessarily computing every subset.
Show all orders containing fries -
for order in powerset("🍔🍟🥤"): # <- input can be a string too!
if "🍟" in order:
print(order)
('🍟',)
('🍔', '🍟')
('🍟', '🥤')
('🍔', '🍟', '🥤')
Sometimes however you will want all of the results, and that's perfectly okay. The natural way to turn an iterable generator to a list is to use the list function -
print(list(powerset("🍔🍟🥤")))
All of the possible orders are collected into a list now -
[(), ('🍔',), ('🍟',), ('🥤',), ('🍔', '🍟'), ('🍔', '🥤'), ('🍟', '🥤'), ('🍔', '🍟', '🥤')]
practice makes permanent
LeetCode (and other sites like it) provided exercises that will often start you with some boilerplate code to fill in -
class Solution:
def subsets(self, nums):
# implement the solution here
Writing code in the template sets you up for failure as it unnecessarily tangles your ordinary functions with self context and makes it difficult to reuse your code elsewhere. As beginners practice over and over, they begin to see this as the correct way to write code. It's not.
Instead write ordinary functions as we have above and simply call them in the awkward Solution class wrapper -
def combinations(...):
...
def powerset(...):
...
class Solution:
def subsets(self, nums):
return powerset(nums) # <- call your function in the wrapper

Sort sub-lists with 2 values with id composed of a string with sequential digits in the end

I have a list composed of sublists:
Each sub-list has always two values in the same order:
[id, value]
Each id is composed of a letter indicating a function (W, F, H or R) than a position level (A to Z)and then a placement/creation order (A sequential number).
So a list would look something like:
[[WA1, value],[WA2, value], [HA3, value]....[WA122, value][HA123,value]]
I have tried to sort using
r.sort(lambda x,y: x[0][1:]) in hopes that I would get a partial string as the key but it failed.
pn = input1
th = Input2
i=0
r=[]
for p in pn:
r.append([p, th[i]])
i+=1
r.sort(lambda x,y: x[0][1:])
I get a Traceback error on the last line.
Any help would be appreciated.
I figured out the answer after trying for some time
sorted(r, key=lambda x: (len(x[0]), x[0][1:]))

Obtaining powers and coefficients of a polynomial on seperate lists

I've tried my best to obtain the powers and coefficients of an arbitrary polynomial given by user on a seperate list.
Basically, only the coefficient part is used and not the power part, but the list of powers(of variables is used for comparison only). I've done it and it works, but the code is kind of sloppy and non-elegant. Is there a better way to code this?
What is should basically do is:
When the user inputs say: 4x3+3 it should return something like:
coeffs = [4,0,0,3]
This is so that I can solve the polynomial using Horner's method.
Here's the runnable code: REPL CODE
The code is run with the test function as:
x = solve(function)
x.parse()
.
#!/usr/bin/python3
######################################################################
#code information
#
#
# When the user provides the input of the form
# 4x3+2x+1
# The parse method is expected to return
# A coefficient list of the provided polynomial
# in ready for use for the horner's method of solving
#######################################################################
function = "4x3+2x+1" #this is the sample input the user is expected to give
#
class solve:
def __init__(self, string):
self.function = string
self.letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z']
#######################################################################
#######################################################################
#######################################################################
#######################################################################
def parse(self):
signs = ['+', '-', '*']
for sign in signs:
self.function = self.function.replace(sign, ' ')#this is where all the
#signs are converted
#to spaces
self.function = self.function.split() #this is where all the
#list is split into terms
self.function.sort(reverse = True) #the polynomial is sorted always
#in the decreasing order
#from higher to lower order of x
coeffs = [] #list that holds all the coefficients
powers = [] #list that holds all the powers
while self.function:
term = self.function.pop(0)#for each term in the polynomial
for letter in self.letters:
#check for the alphabets in the letters(The list above)
if letter in term:
x, y = term.split(letter)
coeffs.append(int(x))#append the coefficient to the list
if y != '':
powers.append(int(y))#append the power to the list
else:
powers.append(1) #append 1 for x ^ 1 term
else:
try:
temp = int(term) #exception occurs here
coeffs.append(temp)#append constant term after exhaution
#of all the polynomial terms
#if no constants exits
#this is not reached
#and neither the line
#directly below
powers.append(0)#only for a constant,we have power 0
break #break nonsense to append only once
except:
pass #exception passed silently
return self.check_complete(coeffs, powers)
print("The coefficients are: ", coeffs)
print("The powers are: ", powers)
#######################################################################
#######################################################################
#######################################################################
#######################################################################
def check_complete(self, coeffs, powers):
"""This function checks if the polynomial is a
complete polynomial that is if it has all the powers of x
it does this by comparing the two lists hand in hand,
that is checks the corresponding terms"""
try:
#while the function arrives here
#power and range are assumed to be of same length
factor = 0 #factor for keeping track of index below
for index in range(len(powers)):
########################################
########################################
Index = index + factor #just cleaning up
########################################
########################################
difference = powers[Index] - powers[Index+1]
while difference > 1:
factor += 1 #factor incremented to keep track
#of where to add
difference -= 1
coeffs.insert(Index+1, 0)#in the coefficient list
#insert zeros where the
#polynomial is missing a term
except:
return coeffs #pass the exception
Yes, you've made this far too complicated. Also, I think you've made an error in the parsing, in that you treat all operators as if they were addition: you change them to spaces and then ignore the differences. I'd test this, but you failed to supply a MCVE.
I suggest some simple steps. Consider the polynomial 1+4x3-2x.
From your text, I gather that you allow only a single variable of a single lower-case letter. Don't go through the trouble of defining an alphabet (which is already in a system package, anyway); simply find the one letter in the string, and store that as the separator, sep.
Scan the string, dividing at any plus or minus sign; keep the sign. This should yield the list ["1", "+4x3", "-2x"].
Scan the list; for any string without the sep variable, append "x0"; for any with no number ahead of sep, prepend a "1"; for any with no number after sep, append a "1"; for any without a leading sign (that can be only the first element of the list", prepend a "+". We now have ["+1x0", "+4x3", "-2x1"].
Now, scan each element of the list. Split at sep and convert the elements to a tuple of integers. [(1, 0), (4, 3), (-2, 1)].
Finally, build your list of coefficients. Let's call the list of tuples terms. Get the highest power and make that the max index of a list of 0's. Then simply assign each coefficient to the location of the corresponding power.
Code:
size = max[z[1] for z in terms] + 1
coeff = [0]*size
for term in terms:
coeff[term[1]] = term[0]

How to create a list or tuple of empty lists in Python?

I need to incrementally fill a list or a tuple of lists. Something that looks like this:
result = []
firstTime = True
for i in range(x):
for j in someListOfElements:
if firstTime:
result.append([f(j)])
else:
result[i].append(j)
In order to make it less verbose an more elegant, I thought I will preallocate a list of empty lists
result = createListOfEmptyLists(x)
for i in range(x):
for j in someListOfElements:
result[i].append(j)
The preallocation part isn't obvious to me. When I do result = [[]] * x, I receive a list of x references to the same list, so that the output of the following
result[0].append(10)
print result
is:
[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]
I can use a loop (result = [[] for i in range(x)]), but I wonder whether a "loopless" solution exists.
Is the only way to get what I'm looking for
result = [list(someListOfElements) for _ in xrange(x)]
This will make x distinct lists, each with a copy of someListOfElements list (each item in that list is by reference, but the list its in is a copy).
If it makes more sense, consider using copy.deepcopy(someListOfElements)
Generators and list comprehensions and things are considered quite pythonic.
There's not really a way to create such a list without a loop of some sort. There are multiple ways of hiding the loop, though, just like [[]] * x hides the loop. There's the list comprehension, which "hides" the loop in an expression (bit it's thankfully still obvious.) There's also map(list, [[]]*x) which has two hidden loops (the one in [[]] * x and the one in map that creates a copy of each list using list().)
There's also the possibility of not creating the list of lists beforehand. The other answers already cover the simple approach, but if that somehow doesn't fit your needs there are other ways. For example, you could make a function that append an empty list to the result list as necessary, and call that:
def append(L, idx, item):
while len(L) <= idx:
L.append([])
L[idx].append(item)
for i in range(x):
for j in someListOfElements:
append(result, i, j)
Or you could use a collections.defaultdict(list) instead of a list:
import collections
result = collections.defaultdict(list)
for i in range(x):
for j in someListOfElements:
result[i].append(j)
That has the benefit of using an already existing type, which is less work, but it does mean you now have a dict (indexed by integers) instead of a list, which may or may not be what you want. Or you could make a class that behaves almost like a list but appends new lists to itself instead of raising IndexError, such as:
import UserList
class defaultlist(UserList.UserList):
def __getitem__(self, idx):
while len(self) <= idx:
self.append([])
return UserList.UserList.__getitem__(self, idx)
result = defaultlist()
for i in range(x):
for j in someListOfElements:
result[i].append(j)
You could write a quick generator function. This would have uses other than this particular case so I'll generalize it a little. Dig this:
def create(n, constructor=list):
for _ in xrange(n):
yield constructor()
Then to make a list of lists,
result = list(create(10))
to make a list of empty dicts,
result = list(create(20, dict))
and (for the sake of completeness) to make a list of empty Foos,
result = list(create(30, Foo))
Of course, you could also make a tuple of any of the above. It wouldn't be too hard to extend it to allow arguments to constructor either. I would probably have it accept a function which accepted an index and returned the arguments to be passed to the constructor.
One last thought is that, because the only requirement that we are placing on constructor is that it be a callable, you could even pass it anything that returns what you want in your list. A bound method that pulls results out of a database query for instance. It's quite a useful little three lines of code.
Why not keep it simple by just appending the list in appropriate loop
result = []
for i in range(x):
result.append([])
for j in someListOfElements:
result[i].append(j)
[Edit: Adding example]
>>> someListOfElements = ['a', 'b', 'c']
>>> x = 3
>>> result = []
>>> for i in range(x):
... result.append([])
... for j in someListOfElements:
... result[i].append(j)
...
>>>
>>> result
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
Please include runnable sample code, so we can run the code ourself to quickly see exactly what it is you want to do. It looks like you just want this:
result = []
for i in range(x):
data = []
for j in someListOfElements:
data.append(j)
# or data = [j for j in someListOfElements]
result.append(data)

Sorting array in ruby

A user has defined the order of columns which is in an array.
order = [:col1, :col2, :col3]
Since the user defined columns order the state of table has changed and the current list of columns is
cols = [:col1, :col4, :col3, :col5]
With the given order cols need to sorted. In this case the sorted columns could look like one of these two cases.
[:col2, :col3, :col4, :col5]
[:col2, :col3, :col5, :col4]
Here is my code to get it working. Wondering if there is a better way.
#get rid of :col2 since it is not present in the cols listing
sanitized_order = order - (order - cols)
sorted_cols = sanitized_order + (cols - sanitized_order)
What do you mean by better? You already accomplished your task pretty handily.
1) This is like yours but 1 readable line.
#order & cols -> provides unique items found in both
#cols - order -> provides columns that are in cols but not order
sorted_cols = (order & cols) + (cols - order)
2)
Here is a way that reads more like a book so someone could follow it line by line to see the logic instead of figuring out the differences in tables:
order = [:col1, :col2, :col3]
cols = [:col1, :col4, :col3, :col5]
sanitized_order = []
order.each do |column|
if cols.include?(column) then
sanitized_order << column
cols.delete(column)
end
end
cols.each do |remainingcolumn|
sanitized_order << remainingcolumn
end
puts sanitized_order
Here's another wordy way to do it:
order = [:col1, :col2, :col3]
cols = [:col3, :col2, :col5, :col4]
sorted_order = cols.sort_by do |c|
if order.index(c)
[1, order.index(c)]
else
[2, cols.index(c)]
end
end
p sorted_order # => [:col2, :col3, :col5, :col4]
Here's how it works. sort_by yields elements of an array to the block; the block should then return something comparable (technically, something that responds to the <=> operator). sort_by uses the <=> operator on the results returned by the block to decide what order the array should be in.
The <=> (spaceship) operator, as you may know, is a binary operator taking two elements a and b. If a < b, it returns -1. If a == b, it returns 0. If a > b, it returns +1.
Arrays respond in an unsurprising way to the <=> operator. The elements of the left array are compared with the elements of the right array in turn, starting with index 0 and increasing. If the a[i] <=> b[i] is != 0, return that result, but if the result is 0, examine the next element. If the last pair of elements compared is 0 (equal) and the arrays are the same size, the arrays are equal and Array.<=> returns 0, otherwise the longer array is considered larger (this example always returns equal size arrays, however).
So, for example:
[2, 1] <=> [2, 2] == -1
[2, 2] <=> [2, 2] == 0
[2, 3] <=> [2, 2] == +1
[1, 2] <=> [2, 1] == +1
So, inside a sort_by, we can use the elements of an array a to indicate primary, secondary, tertiary etc. sort order. a[0] is the primary sort order, a[1] is the secondary sort order, and so on.
All of the columns the customer specified should come first. So, for each column, find its index in customer specified order (order). If that returns a number, then we know that the customer specified that column, and we know its index in the customer-specified list. The primary sort order is 1, because we want the customer specified columns to come first; the secondary sort order is the index, since that gives us the order the customer specified the columns.
If we don't find the column in the order array (that is, order.index(c) returns nil), then we'll 2 as the primary sort order and the index in the master column list (cols) as the secondary sort order. That way all columns the customer did not specify will be last, but in the order they are specified in the laster column list.

Resources