Select lists depending on an item they contain - python

So, I'm trying to create a sudoku solver. Now, I want to check if a number is in it's line, column and square. Can I do it without introducing the line, column and square as function parameters? Is there any way to select the lists that contain an item? Here's my code:
sudoku = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
line1 = [sudoku[0],sudoku[1],sudoku[2],sudoku[3]]
column1 = [sudoku[0],sudoku[4],sudoku[8],sudoku[12]]
square1 = [sudoku[0],sudoku[1],sudoku[4],sudoku[5]]
def sudoku_cellsolver(x):
while sudoku[x] == 0:
number = sudoku[x]+1
if number not in #"List, column, square":
sudoku[x] = number
else:
number = number + 1
#Check another time, etc
while sudoku[x] != 0:
sudoku_cellsolver(x+1)
Any help welcomed. I also have an error when the second branch gets out of range, but I will deal with it later.
EDIT:
Pseudocode:
sudoku = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
l1 = {sudoku[0],sudoku[1],sudoku[2],sudoku[3]} #Converted to set
c1 = {sudoku[0],sudoku[4],sudoku[8],sudoku[12]} #Converted to set
sq1 = {sudoku[0],sudoku[1],sudoku[4],sudoku[5]} #Converted to set
group0 = [l1 | c1 | sq1] #Concatenation of sets
def sudoku_cellsolver(x,group):
if sudoku[x] == 0:
number = sudoku[x]+1
if number not in group:
sudoku[x] = number
The main problem is that I can't use a loop to solve one gap after another because I can't modify the parameter "group0" so that it changes to "group1" inside the function, something I can do with "sudoku[0]" to "sudoku[1]" using the "sudoku[x] = sudoku[x+1]".
If there's no way to change from "group0" to "group1" from inside the function, I'll have to define 16 almost-equal functions where only the "group" changes, and executing them from another function that uses an "if" statement to decide which one of the 16 functions is executed.

Your line1, column1, and square1 variables look like they're defined at the global level, so you should be able to access them like any other variable. You're on the right track with the if thing not in list construct. Try concatenating the lists together to build one list that you can check for membership:
if number not in line1 + column1 + square1:
sudoku[x] = number
This won't work for you if you need to be able to determine which of those lists number is in, but it doesn't look like you wanted to do that anyway.
If you want to modify your globals within a function, you will need to use the global keyword as described in this SO answer.
EDIT (based on comments)
It now appears that you're looking for the zip() function. Zip() groups elements from multiple iterables together by their index. Example:
a = [1,2,3]
b = [4,5,6]
c = [7,8,9]
groups = zip(a, b, c)
for i in xrange(3):
print(groups[i])
Outputs this:
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
Can you use zip() to group your elements together?

Related

Do two boolean colums/lists match? Comparison of two different sized colums: Does a part of one list match a part of the other? (python)

I have different lists of boolean values in different lengths which I will call blists, which I want to compare to a fixed boolean list over time, which I will call blist.
The goal is to find the longest matching series in a list (of blists) in blist.
I want to see if a part or even a whole list of blists can be found somewhere in the list of blist. I would set a minimum of matching values to not overfill my output.
For example (True = T, False = F, example shorter than in real life):
List 1 of blists: (T,T,T,F,T,T,F,F,F,T)
blist: (F,F,T,T,F,F,F,F)
I want to see if a part of list 1 (F,T,T,F,F,F) equals to some part of the list blist.
So for an example blist of (F,F,T,T,F,F,F,F) the output should be, that a part of list 1 can be found in blist.
So output for example:
blist has a similarity with list 1 ((starting point in list 1) 3, (starting point in blist) 1, (length) 6, (part of list that matches): (F,T,T,F,F,F)
I tried .corr() etc., for-loops and if-conditions and nothing wanted to work properly.
This problem probably has a simple solution, but I can't figure it out.
If you want an implementation that determines where exactly the common list starts at each list, here is a simple "for loop" implementation (I used "0,1" instead of "True and False" for sake of readability. you can convert it easily):
a = [0,1,0,1,1,0,0,1,0,1,1,1,0,1,1,1,0,0]
b = [1,1,1,1,1,0,1,1,1,0,0,0,1,1]
list1_start = 0
list2_start = 0
common_list = []
for i in range(len(a)):
for j in range(len(a)-i):
for i2 in range(len(b)):
for j2 in range(len(b)-i2):
if a[i:i+j] == b[i2:i2+j2]:
if len(common_list)<len(a[i:i+j]):
common_list = a[i:i+j]
list1_start = i+1
list2_start = i2+1
print("list1 start: ", list1_start)
print("list2 start: ", list2_start)
print("common_list: ",common_list)
the answer:
list1 start: 10
list2 start: 3
common_list: [1, 1, 1, 0, 1, 1, 1, 0]
I would suggest using something like the KMP algorithm to match subset lists in the whole list. It would utilize O(n) complexity. Making a full implementation use worst of O(n^3) but most likely O(n^2). Solution could look like this:
longest_match = []
for i in range(len(blists)):
if(i+len(longest_match) >= len(blists):
break
for j in range(i+len(longest_match)+1, len(blists)):
if(KMPSearch(blists[i,j], blist)):
longest_match = blists[i,j]
else:
break
Where you loop through each position in blists and check a subset list starting at i and going one past the length of the longest match already found.
one way would be to join the lists into strings and use the "in" and "find" string methods and loops:
l1 = ['T','T','T','F','T','T','F','F','F','T']
blist = ['F','F','T','T','F','F','F','F']
w1, bw = ''.join(l1), ''.join(blist)
all_options = sum([[w1[i:ii] for i in range(len(w1))] for ii in range(len(w1))], [])
all_valid_options = [x for x in all_options if (len(x)>1 and x in bw)]
longest_option = sorted(all_valid_options, key=len)[-1]
w1_start = w1.find(longest_option)
w1_end = w1_start + len(longest_option)
bw_start = bw.find(longest_option)
bw_end = bw_start + len(longest_option)
print(longest_option, len(longest_option), (w1_start, w1_end), (bw_start, bw_end))
FTTFFF 6 (3, 9) (1, 7)

Display only 1 element when it's a repetition

I would like print a result without duplicate with my multiplication
Here an example :
5*3*2=30
2*3*5=30
5*2*3=30
3*2*5=30
.....
All these element are from my list that I browse and you can see it's always =30
So I would like display only the first element (5*3*2) and not others because they are the same.
To be more accurate, here an example what I have :
list = ['5*3*2','5*2*3','2*3*5','2*5*3']
for i in list:
if eval(i) == eval(i)+1 ??? (I dont know how to say the next element)
print(eval(i))
Thanks for reading
Something like this with not in will help you.
#python 3.5.2
list = ['5*3*2','5*2*3','6*9','2*3*5','2*5*3','8*3','9*6']
elm = []
for i in list:
elm_value = eval(i)
if elm_value not in elm:
elm.append(elm_value)
print(elm)
DEMO: https://rextester.com/QKV22875
The comparison:
eval(i) == eval(i)+1
Will compare if the the number i is equal to i + 1, which will always return False. I'm sure you mean to use i as an index and simply wanted to compare if the current element is equal to the next element in the list. However, doing this doesn't really keep track of duplicates, since you have to consider everything else in the list.
Its also not a good idea to use list as a variable name, since it shadows the builtin function list. Plenty of other suitable names you can use.
One way is to use a set to keep track of what items you have seen, and only print items that you have seen for the first time:
lst = ["5*3*2","5*2*3","2*3*5","2*5*3"]
seen = set()
for exp in lst:
calc = eval(exp)
if calc not in seen:
print(calc)
seen.add(calc)
If you are always dealing with simple multiplying expressions with the * operator(no brackets), you could also use functools.reduce and operator.mul instead to multiply the numbers instead of eval here. This will first split the numbers by *, map each number string to an integer, then multiply every element with each other.
from operator import mul
from functools import reduce
lst = ["5*3*2","5*2*3","2*3*5","2*5*3"]
seen = set()
for exp in lst:
numbers = map(int, exp.split("*"))
calc = reduce(mul, numbers)
if calc not in seen:
print(calc)
seen.add(calc)
Output:
30
With the following list:
l = ['5*3*2','5*2*3','2*3*5','2*5*3', '2*2']
(Note that list is already something in python so I wouldn't recommend using that as a variable name)
I would first create a list of unique values:
unique_vals = set(map(eval, list))
set([4, 30])
Then for each unique values get the first match in l:
[next(x for x in l if eval(x) == i) for i in unique_vals]
I get:
['2*2', '5*3*2']
Is that what you want?

meaning of ",0" at the end

When I remove the ",0" it throws error and when it is there it shows the right output. I want to know the use of it.
import sys
from collections import Counter
input()
socks,pairs = Counter(map(int,input().strip().split())),0
for s in socks:
pairs = pairs + socks[s] // 2
print(pairs)
You're assigning to two variables (socks and pairs) in this line:
socks,pairs = Counter(map(int,input().strip().split())),0
If you omit ,0, it's like writing:
socks = Counter(map(int,input().strip().split()))
pairs =
Hence the error.
This:
socks, pairs = Counter(map(int,input().strip().split())), 0
translates to this:
(socks, pairs) = (Counter(map(int,input().strip().split())), 0)
It's as if you wrote :
socks = Counter(map(int,input().strip().split()))
pairs = 0
The difference being right side is fully evaluated before assignments, but it doesn't matter here
But the sizes of tuples must match. When you omit ,0 it becomes:
(socks, pairs) = (Counter(map(int,input().strip().split())), )
As you can see, the sizes don't match. This is what causes the problem.
This is called a tuple assignment. for example, if you want to initiate two variables x and y and assign two values a and b for them you can do it with like:
x = a
y = b
or just:
x, y = a, b
in this case, the first value 'a' will be assigned to the first variable 'x' and the second value 'b' will be assigned to the second variable 'y'. In this is very powerful to swap two values without using a temp variable as follows:
x, y = y, x
in your case you are initiating two variables: socks and pairs so they must be followed by two values. In your case:
socks = Counter(map(int, input().strip().split()))
pairs = 0
So, it's pretty obvious that you can't assign one value to two variables. so you can't remove the 0 (pairs initial value) which is a reserved variable to accumulate on it while looping.

How to create a random sample of [n] elements for each unique element in list containing a certain string(with nested-loops?)

I am trying to create a list which contains a random sample (more specifically, a stratified sample).
My data consists of a list with several million telephone numbers (a string for each) which I splitted into a list containing 2 strings (for each number).
The first string is the city code, by which the sample has to be stratified. I used
unique = list(set(citycode))
to get all unique elements from the main list (mainlist[0]).
Suppose I have ~1000 elements in list 'unique' and for each unique element I am trying to find 5 elements in 'mainlist' randomly which contain the number of unique[i] in mainlist[i][0].
For each match, both fields/strings of mainlist shall be appended to a new list, 'randomlist'. So the final list should contain 5000 telephone numbers.
I thought of using nested loops for this, but as I am a beginner in Python and trying to use online tutorials to teach myself, I haven't really found a function or way to solve this.
I am not sure in this case what would be a possible way of solving it.
Any ideas or input would be greatly appreciated.
Thank you!
Assuming two lists like:
main = [(123, xxxxxxx),...]
unique = [123, ...]
Then you can do something like:
from random import shuffle
shuffle(main)
out = []
for u in unique:
i = 0
it = (x for x in main if x[0] == u)
while i < 5:
try:
out.append(main.pop(main.index(next(it))))
except:
pass
i+=1
out will contain a list of tuples like those found in main, up to 5 per unique area code (will be less than 5, if main contains less than 5), randomly distributed.
UPDATE
Since you want to exclude area codes with too little representation all together, here's how you do that:
from random import shuffle
from collections import Counter
c = Counter(x[0] for x in main)
main = [x for x in main if c[x] >= 5]
shuffle(main)
out = []
for u in unique:
i = 0
it = (x for x in main if x[0] == u)
while i < 5:
out.append(main.pop(main.index(next(it))))
i+=1

Variable nesting in Python

Basically, I need to make my program able to create multiple (unlimited) variables for me, that I will still be able to use manipulate through my code, without me defining them.
I was thinking to have a letter and a number as the variable name, such as a1, and have the program create new variables just adding 1 to the number. So it would create a1 through a30 or so. How would I do this?
My program is going to add polynomials and the variables (or list now) is to separate the different monomials, and since I don't know how many monomials there will be in the polynomial, I needed a way to make the number flexible so I have an exact amout of spaces for the monomials, no extras, and no less.
Here's the code:
# Sample polynomial set to x, the real code will say x = (raw_input("Enter a Polynomial")).
x = '(5xx + 2y + 2xy)+ (4xx - 1xy)'
# Isdigit command set to 't' to make the code easier to write.
t = str.isdigit
# Defining v for later use.
v = 0
# Defining 'b' which will be the index number that the program will look at.
b = 1
# Creating 'r' to parse the input to whatever letter is next.
r = x [b]
# Defining n which will be used later to tell if the character is numeric.
n = 0
# Defining r1 which will hold one of the monomials, ( **will be replaced with a list**)
#This was the variable in question.
r1 = ''
# Setting 'p' to evaluate if R is numeric ( R and T explained above).
p = t(r)
# Setting 'n' to 1 or 0 to replace having to write True or False later.
if p == True:
n = 1
else:
n = 0
# Checking if r is one of the normal letters used in Algebra, and adding it to a variable
if r == 'x':
v = 'x'
c = 1
elif r == 'y':
v = 'y'
c = 1
elif r == 'z':
v = 'z'
c = 1
# If the character is a digit, set c to 0, meaning that the program has not found a letter yet (will be used later in the code).
elif n == 1:
v = r
c = 0
# Adding what the letter has found to a variable (will be replaced with a list).
r1 = r1 + v
b = b + 1
I will eventually make this a loop.
I added comments to the code so it's more understandable.
Essentially, you are trying to programmatically, dynamically modify the heap space where the variables live. I really do not think this is possible. If it is, it is very obscure.
I do understand where you are coming from. When I was first learning to program I had thought to solve problems in ways that would require such "dynamically created" variables. The solution really is to recognize what kind of (collection) data structure fits your needs.
If you want variables a1 through a30, create a list a. Then a1 would be a[1], a30 would be a[30]. It is a little different to write, but it should give you the behavior you need.
I spent at least five minutes trying to think why you would want to do this in the first place, until I decided I could actually write the code in less than five minutes, and hoping that in return you'd tell us why you want to do this.
Here's the code:
def new(value):
highest = -1
for name in globals():
if name.startswith('a'):
try:
number = int(name[1:])
except:
continue
if number > highest:
highest = number
globals()['a%d' % (highest + 1, )] = value
new("zero")
new("one")
new("two")
print a2 # prints two

Categories