Python: Permutate 2 Lists Simultaneously Until Requirement is Met - list

To Begin, I am using two lists and adding them to the "mask" to get the new lists we will be permutating.
list1 = [1,0,1]
| | | |
v v v v
mask = [2,1,2]
new_list1 = [3,1,3]
list2 = [0,1,0]
| | | |
v v v v
mask = [2,1,2]
new_list2 = [2,2,2]
So, next is permutating new_list1 and new_list2 until they equal the original list1 and list2.
1 Create a set of "rules" that resemble subtracting the "mask".
2 Permutate new_list1 and new_list2.
3 Pass the permutated new lists through the set of "rules".
4 If the new_list1 and new_list2 are equal to list1 and list2, STOP
Else: Continue
This is how I could do the one list alone, however, I am trying to do both new_list1 and new_list2 at the same time.
from itertools import permutations
from itertools import zip_longest
list1 = [1,0,1]
list2 = [0,1,0]
mask = [2,1,2]
new_list1 = [3,1,3]
new_list2 = [2,2,2]
rules = {(2,3):1,(2,2):0,(1,3):2,(2,1):-1,(1,1):0,(1,2):1}
repeat = 1
while repeat == 1:
perm = list(permutations(new_list1))
for i in perm:
guess = [rules[pair] for pair in zip(mask,new_list1)]
if guess == list1:
repeat = 0
break
print("Guess:",guess)
OUTPUT: Guess: [1,0,1]
Is there a way I can permutate new_list1 and new_list2 together until they are both true?
from itertools import permutations
list1 = [1,0,1]
list2 = [0,1,0]
mask = [2,1,2]
new_list1 = [3,1,3]
new_list2 = [2,2,2]
combined = [[1,0,1],[0,1,0]]
rules = {(2,3):1,(2,2):0,(1,3):2,(2,1):-1,(1,1):0,(1,2):1}
repeat = 1
while repeat == 1:
perm = list(permutations(new_list1, new_list2))
for i in perm:
guess_combined = []
guess = [rules[pair] for pair in zip(mask,new_list1)]
guess_2 = [rules[pair] for pair in zip(mask,new_list2)]
guess_combined.append(guess,guess_2)
if guess_combined == combined:
repeat = 0
break
print("Guess:",guess)
This is my attemp, however, it gives Error:
11 repeat = 1
12 while repeat == 1:
---> 13 perm = list(permutations(new_list1, new_list2))
14 for i in perm:
15 guess_combined = []
TypeError: Expected int as r

Related

Find maximum and minimum of multivariable function in sympy

I have the following function:
f = x**2 + y**2
I would like to use sympy to find the maximum of and minimum value in the unit square [0,1] in x and [0,1] in y.
The expected outcome would be 0 for point [0,0] and 2 for point [1,1]
Can this be achieved?
I did something clunky, but appears to work [although not fast]:
def findMaxMin(f):
# find stationary points:
stationary_points = sym.solve([f.diff(x), f.diff(y)], [x, y], dict=True)
# Append boundary points
stationary_points.append({x:0, y:0})
stationary_points.append({x:1, y:0})
stationary_points.append({x:1, y:1})
stationary_points.append({x:0, y:1})
# store results after evaluation
results = []
# iteration counter
j = -1
for i in range(len(stationary_points)):
j = j+1
x1 = stationary_points[j].get(x)
y1 = stationary_points[j].get(y)
# If point is in the domain evalute and append it
if (0 <= x1 <= 1) and ( 0 <= y1 <= 1):
tmp = f.subs({x:x1, y:y1})
results.append(tmp)
else:
# else remove the point
stationary_points.pop(j)
j = j-1
# Variables to store info
returnMax = []
returnMin = []
# Get the maximum value
maximum = max(results)
# Get the position of all the maximum values
maxpos = [i for i,j in enumerate(results) if j==maximum]
# Append only unique points
append = False
for item in maxpos:
for i in returnMax:
if (stationary_points[item] in i.values()):
append = True
if (not(append)):
returnMax.append({maximum: stationary_points[item]})
# Get the minimum value
minimum = min(results)
# Get the position of all the minimum values
minpos = [i for i,j in enumerate(results) if j==minimum ]
# Append only unique points
append = False
for item in minpos:
for i in returnMin:
if (stationary_points[item] in i.values()):
append = True
if (not(append)):
returnMin.append({minimum: stationary_points[item]})
return [returnMax, returnMin]

python compare items in 2 list of different length and sequence/ duplicates should be considered

I'm trying to compare two lists of unequal length
list1=['a','b','d','b','c','d','e','f']
list2=['a','b','d','d']
list1 should be compared until the last element in list2(which is 'd') is found in list1.
Below is the desired output
output = ['b','c']
below is the code which i have
i = 0
j = 0
output = []
while(True):
if(list1[i] == list2[j]):
i += 1
j += 1
if (j == len(list2)):
break
else:
output.append(list1[i])
i = i + 1
is there any better way of doing the same?
Thanks for helping!
I think you want itertools.takewhile
from itertools import takewhile
def taker(l1, l2):
it = iter(l1)
for j in l2:
yield from takewhile(lambda x: x!=j, it)
list(taker(list1, list2)) is ['b', 'c']

Plot specific lines for specific values with Pyplot

I'm trying to plot two files of data of this type:
name1.fits 0 0 2.40359218172
name2.fits 0 0 2.15961244263
The third column has values from 0 to 5. I want to plot column 2 vs column 4, but, for lines with values in col 3 less than 2 (0 and 1), I want to shift col 2 by -0.1, and for lines with values greater than 3 (4 and 5) I want to shift col 2 by +0.1.
However my code seems to be shifting all values by +0.1. Here is what I have so far:
import matplotlib.pyplot as plt
import numpy as np
with open('file1.txt') as data, open('file2.txt') as stds:
lines1 = data.readlines()
lines2 = stds.readlines()
x1a = []
x2a = []
x1b = []
x2b = []
x1c = []
x2c = []
y1a = []
y2a = []
y1b = []
y2b = []
y1c = []
y2c = []
for line1 in lines1:
p = line1.split()
if p[2] < 2:
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < p[2] < 4:
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif p[2] > 3:
x1c.append(float(p[1]))
y1c.append(float(p[3]))
for line2 in lines2:
q = line2.split()
if q[2] < 2:
x2a.append(float(q[1]))
y2a.append(float(q[3]))
elif 1 < q[2] < 4:
x2b.append(float(q[1]))
y2b.append(float(q[3]))
elif q[2] > 3:
x2c.append(float(q[1]))
y2c.append(float(q[3]))
x1a = np.array(x1a)
x2a = np.array(x2a)
x1b = np.array(x1b)
x2b = np.array(x2b)
x1c = np.array(x1c)
x2c = np.array(x2c)
y1a = np.array(y1a)
y2a = np.array(y2a)
y1b = np.array(y1b)
y2b = np.array(y2b)
y1c = np.array(y1c)
y2c = np.array(y2c)
minorLocator = AutoMinorLocator(5)
fig, ax = plt.subplots(figsize=(8, 8))
fig.subplots_adjust(left=0.11, right=0.95, top=0.94)
plt.plot(x1a-0.1,y1a,'b^',mec='blue',label=r'B0',ms=8)
plt.plot(x2a-0.1,y2a,'r^',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.plot(x1b,y1b,'bo',mec='blue',label=r'B0',ms=8)
plt.plot(x2b,y2b,'ro',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.plot(x1c+0.1,y1c,'bx',mec='blue',label=r'B0',ms=8)
plt.plot(x2c+0.1,y2c,'rx',mec='red',fillstyle='none',mew=0.8,ms=8)
plt.axis([-1.0, 3.0, 0., 4])
ax.xaxis.set_tick_params(labeltop='on')
ax.yaxis.set_minor_locator(minorLocator)
plt.show()
Here is the plot:
plot
I'm pretty sure the problem is in my "ifs". I hope you can clear the way and/or show me a better option for this.
When you do your queries (if) you must ensure the conversion happens before the question so:
for line1 in lines1:
p = line1.split()
if p[2] < 2:
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < p[2] < 4:
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif p[2] > 3:
x1c.append(float(p[1]))
y1c.append(float(p[3]))
, should actually be:
for line1 in lines1:
p = line1.split()
if float(p[2]) < 2: # changed here
x1a.append(float(p[1]))
y1a.append(float(p[3]))
elif 1 < float(p[2]) < 4: # There seems to be a problem with this if
x1b.append(float(p[1]))
y1b.append(float(p[3]))
elif float(p[2]) > 3: # changed here
x1c.append(float(p[1]))
y1c.append(float(p[3]))
The same for your q variables. Also notice that asking 1 < x < 4 will intercept with x > 3 and x < 2. You should also correct this.

Merge Lists with same first index but other second index

I am working on a search algorithm in python but there is something I don't get to work..
I have a list which looks like this [["A","1.txt"],["A","2.txt"],["A","3.txt"],["B","1.txt"],["B","3.txt"]]
Now I want to merge the sub-lists that have the same first index. So the result would be:
[["A",["1.txt","2.txt",3.txt"]],["B",["1.txt"],["3.txt"]]]
Anyone who knows how to do this...
Kinda got a sort (on mergesort basis) but this does not merge the tuples
def merge_pairs(data):
if len(data) <= 1 :
return data[:]
else:
mid = len(data) // 2
fst = merge_pairs(data[:mid])
snd = merge_pairs(data[mid:])
res = []
fi = 0
si = 0
while fi < len(fst) and si < len(snd):
if fst[fi][0] < snd[si][0] or fst[fi][0] == snd[si][0] and fst[fi][1] < snd[si][1]:
res.append(fst[fi])
fi = fi + 1
else:
res.append(snd[si])
si = si + 1
if fi < len(fst) :
res.extend(fst[fi:])
elif si < len(snd) :
res.extend(snd[si:])
return res
So i'd like not to use the dict() function of python
Thanks in advance
The easiest way (which may or may not be slower than the hard way) is to use a defaultdict:
>>> from collections import defaultdict
>>> result = defaultdict(list)
>>> mylist = [["A","1.txt"],["A","2.txt"],["A","3.txt"],["B","1.txt"],["B","3.txt"]]
>>> for key, value in mylist:
... result[key].append(value)
...
>>> print(sorted(result.items()))
[('A', ['1.txt', '2.txt', '3.txt']), ('B', ['1.txt', '3.txt'])]
The hard way (if your data is truly already sorted):
>>> src = [["A","1.txt"],["A","2.txt"],["A","3.txt"],["B","1.txt"],["B","3.txt"]]
>>> prev = None
>>> dst = []
>>> for key, value in src:
... if key != prev:
... prev = key
... dst.append((key, []))
... dst[-1][-1].append(value)
...
>>> print(dst)
[('A', ['1.txt', '2.txt', '3.txt']), ('B', ['1.txt', '3.txt'])]
But note that Python sort is really, really fast, and Python loops like this... Not so much.
Edit According to your comment below, you also want counts. Again there is a dictionary way:
>>> from collections import defaultdict
>>> result = defaultdict(lambda: defaultdict(int))
>>> mylist = [["A","1.txt"],["A","2.txt"],["A", "2.txt"],["A","3.txt"],["B","1.txt"],["B","3.txt"]]
>>> for key, value in mylist:
... result[key][value] += 1
...
>>> print(sorted((x, sorted(y.items())) for (x, y) in result.items()))
[('A', [('1.txt', 1), ('2.txt', 2), ('3.txt', 1)]), ('B', [('1.txt', 1), ('3.txt', 1)])]
and a loop way:
>>> src = [["A","1.txt"],["A","2.txt"],["A", "2.txt"],["A","3.txt"],["B","1.txt"],["B","3.txt"]]
>>> prevkey, prevvalue = None, None
>>> dst = []
>>> for key, value in src:
... if key != prevkey:
... prevkey = key
... prevvalue = None
... dst.append((key, []))
... if value != prevvalue:
... prevvalue = value
... dst[-1][-1].append([value, 0])
... dst[-1][-1][-1][-1] += 1
...
>>> dst
[('A', [['1.txt', 1], ['2.txt', 2], ['3.txt', 1]]), ('B', [['1.txt', 1], ['3.txt', 1]])]
You'd really want to run timeit to be sure, but in this instance, the loop way almost looks guaranteed to be slower (and of course, the dictionary way doesn't require you to do a pre-sort.)

Python: simple list modify task

I need to remove the unique elements of the list, the first thought is:
def cut_uniq(data):
for x in data:
if data.count(x) == 1:
data.remove(x)
print(data)
cut_uniq([1, 2, 3, 4, 5,])
return
[2, 4]
please, tell me why?
Look at each iteration:
i x data
0 1 [1,2,3,4,5]
1 3 [2,3,4,5]
2 5 [2,4,5]
[2,4]
You can iterate over a different list than you are modifying. This returns a copy of the list
def cut_uniq(data):
return [x for x in data if data.count(x) > 1]
or more efficiently
from collection import Counter
def cut_uniq(data):
return [x for x, count in Counter(data) if count > 1]
If you really do want to modify the original list, and not return a copy
def cut_uniq(data):
i = 0
while i < len(data):
if data.count(data[i]) == 1:
del data[i]
else:
i += 1
or
from collections import Counter
def cut_uniq(data):
for x, count in Counter(data):
if count == 1:
data.remove(x)
95% of the time that you modify the same list as you're iterating over, you'll have problems.
When you use
for x in data:
it translates to
for i in [0,1,2,3,4]:
x = data[i]
So in the first loop, i = 0 data[i]=1. you remove 1 from data, the data is [2,3,4,5]
on the second loop , i = 1, because now data is [2,3,4,5], data[i] = 3. So 2 is left in the data list and never been visited.
Same as the number 4.
So when you finished your loop, the [2,4] leted in the list.