remove minimum items from two list to make lists same - python

I have two lists with same items and different orders.
for example:
a = [4, 2, 3, 1]
b = [2, 3, 1, 4]
Which item(s) should I remove to make lists same?
Here: [4] is an answer, so:
a = [2, 3, 1]
b = [2, 3, 1]
But [2, 4] or [2, 3, 1] are also answers, if I remove [2, 3, 1]:
a = [4]
b = [4]
I need to remove the minimum number of elements, here [4] is the optimal solution.
Another example:
a = [1, 2, 3, 4]
b = [2, 1, 4, 3]
Possible answers:
[1, 3]
[1, 4]
[2, 3]
[2, 4]
Order of algorithm is unimportant.

I would certainly search for the longest common subsequence first (google LCS, many algorithms are available, e.g. on algorithmist), then if you remove the LCS elements from one of the original list you got the shortest list of elements to remove. In pseudocode :
lcs = LCS(a,b)
res = copy(a)
foreach element e in lcs
remove(res,e)
return res

Related

How to check if a 2D list contains a list that partly contains another list

I'm trying to find out if my Tabu list (2D) contains a list that partly contains another list.
Like:
Tabu = [[1, 2, 3], [3, 2, 1, 0]]
Test = [3, 2, 1]
Test2 = [1, 3, 2]
Here Tabu contains a list: [3, 2, 1, 0] that contains [3, 2, 1], so Tabu contains Test, but doesn't contain Test2 as there are no lists in Tabu that contain [1, 3, 2] in this order.
Note: All values of Test must be in a sublist of Tabu to pass.
Changing the lists to sets is not an option. There are no repeating values in Test and only two seperate lists can contain the same value in Tabu.
Edit: More info and clarification
you need to iterate through the Tabu and check if all element of the Test list are in the sublist of Tabu
>>> Tabu = [[1, 2, 3], [4, 5, 6, 0]]
>>> Test = [4, 5, 6]
>>>
>>> result = any(all(i in sublist for i in Test) for sublist in Tabu)
>>> result
True
>>>

find occurrences of elements of a list in a list of list

i have a list [1, 2, 3]
i want to find number of times the elements of this list appears in a list of list:
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
occurrences = 4
What I’m doing currently is the following:
a = [1, 2, 3]
lol = [[1, 2, 4, 5], [2, 3, 1, 2], [1, 2, 3], [3, 2, 6, 7, 1], [1, 4, 2, 6, 3]]
def get_count(a, b):
a = set(a)
return sum([a.issubset(x) for x in b])
print(get_count(a, lol))
This method works but is quite slow when I have 100s of 1000s of list to compare with a list of list (lol remains static!)
can we also preserve the "order" of the elements? there can be other elements in between. in this case occurrences will be 2 for the above case
Why not try:
testlist = lol ##Create a test list that we will work with
for i in range len(testlist): ##Start a loop that will repeat length of testlist times
if a in testlist: ##If/When it finds the first occurrence of the list a
Occurrences =+ 1 ##It adds 1 to the amount off occurences
Pos = testlist.index(a)
testlist.del(Pos) ##It deletes the instance from the list.
This should work

Indexing with loops in python

The question asks to write a function that takes in some unordered list and from that unordered list pull any sublist that is ordered. Example [5, 2, 1, 3, 4] would become [1,3,4]. My issue is in indexing, I want a way to express that if the current iteration is greater than the one before it, I want to add it. However, the problem that my code runs into is that it compares the first and last of an item.
For my code: [5, 2, 1, 3, 4] => [5,1,3,4]
def numIncreasing(lst):
ans=[]
for index in range(len(lst)):
if lst[index]>=lst[index-1]:
ans.append(lst[index])
elif lst[index]<lst[index-1] and lst[index]<lst[index+1]:
ans.append(lst[index])
else:
continue
return ans
edit: fixed the code not recognizing the start of the pattern
Here is an algorithm that finds the largest ordered sublist:
def increasing2(lst):
length = len(lst)
for size in range(length, 1, -1):
for start in range(0, length - size + 1):
curr = lst[start:start+size]
if all(x <= y for x, y in zip(curr, curr[1:])):
return curr
return None
Which behaves as follows:
>>> increasing2([5, 2, 1, 3, 4])
[1, 3, 4]
Logic of approach:
Loop over all sublists in reversed order, so the largest sublists come before the smaller sublists:
[5, 2, 1, 3, 4]
[5, 2, 1, 3]
[2, 1, 3, 4]
[5, 2, 1]
[2, 1, 3]
[1, 3, 4]
[5, 2]
[2, 1]
[1, 3]
[3, 4]
If the current list is sorted, return it. Otherwise keep going through all the sub lists in order from largest to smallest length. This ensures that you get the largest sublist first. The algorithm also only considers sublists of length 2 or greater.

Operations on sub-lists in list

I have a list of lists:
a = [[1, 2], [2, 3], [4, 3]]
How to get the following effect in two steps ?:
b = [[1, 2, 2, 3], [1, 2, 4, 3], [2, 3, 4, 3]]
b = [[1, 2, 3], [1, 2, 4, 3]], it means:
1.1. If the same values occur in the sub-list b[i] next to each other, then
one of these values must be deleted.
2.2. If the same values appear in a given sub-list b[i] but not next to each
other, then the entire sub-list b[i] must be deleted.
timegb is right. An elegant solution involves some amount of trickery and deception. I'll try and break down the steps.
find all 2-combinations of your input using itertools.combinations
flatten returned combinations with map and chain
for each combination, group by consecutive elements
keep only those that satisfy your condition by doing a length check.
from itertools import chain, combinations, groupby
out = []
for r in map(lambda x: list(chain.from_iterable(x)), combinations(a, 2)):
j = [i for i, _ in groupby(r)]
if len(j) <= len(set(r)):
out.append(j)
print(out)
[[1, 2, 3], [1, 2, 4, 3]]
If you need only the first part, just find combinations and flatten:
out = list(map(lambda x: list(chain.from_iterable(x)), combinations(a, 2)))
print(out)
[[1, 2, 2, 3], [1, 2, 4, 3], [2, 3, 4, 3]]

All ways of partitioning a list into two non-empty lists

[0.0, 1.0, 2.0, 3.0, 4.0]
I have 5 numbers and two groups, left and right.
Each number has two choices - it can go left or right.
I need a list that contains all partitioning of the list [0,1,2,3,4] into two non empty parts. For example: [([0], [1,2,3,4]), ([0,1], [2,3,4]), ...,]
Note that there are a total of (2^5 -2)/2 partitioning - order doesn't matter and I don't want repeats. Meaning I don't want something like this (if my list was [1,2,3,4]):
[] [1, 2, 3, 4]
[1] [2, 3, 4]
[2] [1, 3, 4]
[1, 2] [3, 4]
[3] [1, 2, 4]
[1, 3] [2, 4]
[2, 3] [1, 4]
[1, 2, 3] [4]
[4] [1, 2, 3]
[1, 4] [2, 3]
[2, 4] [1, 3]
[1, 2, 4] [3]
[3, 4] [1, 2]
[1, 3, 4] [2]
[2, 3, 4] [1]
[1, 2, 3, 4] []
I've looked into all of the itertools functions and none seem to work.
Edit:
for list [i for i in range(16)], which has 16 elements, If I do the following, this is what I see:
n = len(l)//2 + 1
>>> xs = list(chain(*[combinations(l, i) for i in range(1, n)]))
>>> pairs = [(list(x), list(set(l) - set(x))) for x in xs]
>>> print len(pairs)
39202
>>> (2**16-2)/2
32767
In fact, it doesn't work for a list with 6 elements either. I don't see why...
The problem occurs for all even length lists. For example, when I try a length 2 list, I get:
[([0.0], [1.0]), ([1.0], [0.0])]
The stuff is there in itertools, maybe you just weren't looking in the right places.
Here is teh codez:
from collections import OrderedDict
from itertools import chain, combinations
def partition(L):
n = len(L)//2 + 1
xs = chain(*[combinations(L, i) for i in range(1, n)])
pairs = (tuple(sorted([x, tuple(set(L) - set(x))])) for x in xs)
return OrderedDict.fromkeys(pairs).keys()
Output:
>>> for pair in partition([1,2,3,4]):
... left, right = map(list, sorted(pair, key=len))
... print left, right
...
[1] [2, 3, 4]
[2] [1, 3, 4]
[3] [1, 2, 4]
[4] [1, 2, 3]
[1, 2] [3, 4]
[1, 3] [2, 4]
[1, 4] [2, 3]

Categories

Resources