How do I create an iterator over a recursive data structure in Crystal? - crystal-lang

I have a tree structure and currently I am trying to return an iterator that iterates over the elements of the datastructure so that my function can accept a block.
I have currently reduced my code to this:
# tree.cr
class Tree
property children : Array(Tree)
def initialize(#value : Int32)
#children = [] of Tree
end
def add(child : Tree)
#children << child
end
def each_leaf : Iterator(Int32)
Iterator.chain [{#value}.each, #children.each.flat_map(&.each_leaf)]
end
end
root = Tree.new 3
root.add Tree.new 1
root.add Tree.new 5
p root.each_leaf.to_a # no output from here
p "hi" # no output from here either
Interestingly the code snippet above simply terminates, and the second print p "hi" doesn't get executed either.
Would love to hear pointers on how this code could be corrected. Thanks in advance.
Edit:
Here are some details of the executing environment
Crystal Version: v1.7.2
Command: crystal run tree.cr
Output: Program received and didn't handle signal TRAP (5)
System: M1 Macbook Pro, Monterey 12.6

Related

Why won't my list.append() not append despite working in print output

Below is my code for the leet code problem: here
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
tripletsList = []
uniqueNums = set(nums)
uniqueNums = list(nums)
for x in range(len(uniqueNums)):
for y in range(len(uniqueNums)):
for z in range(len(uniqueNums)):
print(uniqueNums[x],uniqueNums[y],uniqueNums[z])
if (uniqueNums[x] + uniqueNums[y] + uniqueNums[z]) == 0:
if [[uniqueNums[x],uniqueNums[y],uniqueNums[z]]] not in tripletsList:
tripletsList.append([uniqueNums[x],uniqueNums[y],uniqueNums[z]])
print(tripletsList)
I realize it isn't the optimal solution but in my print line the output shows the correct combination, yet my final triplets list is not eliminating anything which leads me to believe I am not using the "not in" function of python correctly. Any help is greatly appreciated and I must be missing something that is just trivial
I tried first printing every combination of the unique list (yes tons of overlap), then I tried limiting the triplets that made it pass the == 0 check to only triplets that were not already in the triplets list (failed)

How can I share an updated values in dictionary among different process?

I am newbe here and also in Python. I have a question about dictionaries and multiprocessing. I want to run this part of the code on the second core of my Raspberry Pi (on first is running GUI application). So, I created a dictionary (keys(20) + array with the length of 256 for each of this key - script below is just short example). I initialized this dictionary in a separate script and put all values inside this dictionary on zero. Script table1.py (this dictionary should be available from both cores)
diction = {}
diction['FrameID']= [0]*10
diction['Flag']= ["Z"]*10
In the second script (should run on the second core), I read the values that I get from the serial port and put/set them in this dictionary (parsing + conversion) according to the appropriate place. Since I get much information through a serial port, the information is changing all the time. Script Readmode.py
from multiprocessing import Process
import time
import serial
import table1
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i, j)
return text
def hexTobin(hex_num):
scale = 16 ## equals to hexadecimal
num_of_bits = len(hex_num)*4
bin_num = bin(int(hex_num, scale))[2:].zfill(num_of_bits) #hex to binary
return bin_num
def readSerial():
port = "/dev/ttyAMA0"
baudrate = 115200
ser = serial.Serial(port, baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, xonxoff=False, rtscts=False)
line = []
for x in xrange(1):
ser.write(":AAFF:AA\r\n:F1\r\n") # new
while True:
for c in ser.read():
line.append(c)
a=''.join(line[-2:])
if a == '\r\n':
b=''.join(line)
print("what I get:" + b)
c=b[b.rfind(":"):len(b)] #string between last ":" start delimiter and stop delimiter
reps = {':':'', '\r\n':''} #throw away start and stop delimiter
txt = replace_all(c, reps)
print("hex num: " + txt)
bina_num=hexTobin(txt) # convert hex to bin
print("bin num: " + bina_num)
ssbit = bina_num[:3] # first three bits
print("select first three bits: " + ssbit)
abit=int(ssbit,2) # binary to integer
if abit == 5:
table1.diction['FrameID'][0]=abit
if abit == 7:
table1.diction['FrameID'][5]=abit
print("int num: ",abit)
print(table1.diction)
line = []
break
ser.close()
p1=Process(target=readSerial)
p1.start()
During that time I want to read information in this dictionary and use them in another process. But When I try to read that values there are all zero.
My question is how to create a dictionary that will be available for both process and can be updated based on data get from serial port?
Thank you for your answer in advance.
In Python, when you start two different scripts, even if they import some common modules, they share nothing (except the code). If two scripts both import table1, then they both have their own instance of the table1 module and therefore their own instance of the table1.diction variable.
If you think about it, it has to be like that. Otherwise all Python scripts would share the same sys.stdout, for example. So, more or less nothing is shared between two different scripts executing at the same time.
The multiprocessing module lets you create more than one process from the same single script. So you'll need to merge your GUI and your reading function into the same script. But then you can do what you want. Your code will look something like this:
import multiprocessing
# create shared dictionary sd
p1=Process(target=readSerial, args = (sd,)
p1.start()
# create the GUI behaviour you want
But hang on a minute. This won't work either. Because when the Process is created it starts a new instance of the Python interpreter and creates all its own instances again, just like starting a new script. So even now, by default, nothing in readSerial will be shared with the GUI process.
But fortunately the multiprocessing module provides some explicit techniques to share data between the processes. There is more than one way to do that, but here is one that works:
import multiprocessing
import time
def readSerial(d):
d["test"] = []
for i in range(100):
l = d["test"]
l.append(i)
d["test"] = l
time.sleep(1)
def doGUI(d):
while True:
print(d)
time.sleep(.5)
if __name__ == '__main__':
with multiprocessing.Manager() as manager:
sd = manager.dict()
p = multiprocessing.Process(target=readSerial, args=(sd,))
p.start()
doGUI(sd)
You'll notice that the append to the list in the readSerial function is a bit odd. That is because the dictionary object we are working with here is not a normal dictionary. It's actually a dictionary proxy that conceals a pipe used to send the data between the two processes. When I append to the list inside the dictionary the proxy needs to be notified (by assigning to the dictionary) so it knows to send the updated data across the pipe. That is why we need the assignment (rather than simply directly mutating the list inside the dictionary). For more on this look at the docs.

print values from list inside a list

i have this code in python:
sensor16=['1','-','\\','/','*','!']
sensor15=['4','G','H','I']
sensor14=['7','P','Q','R','S']
sensor13=['*']
sensor12=['2','A','B','C']
sensor11=['5','J','K','L']
sensor10=['8','T','U','V']
sensor09=['0',' ']
sensor08=['3','D','E','F']
sensor07=['6','M','N','O']
sensor06=['9','W','X','Y','Z']
sensor05=['#']
sensor04=['BACKSPACE']
sensor03=['DELETE ALL']
sensor02=['READ']
sensor01=['TRANSMITE']
sensor= [sensor01,sensor02,sensor03,sensor04,sensor05,sensor06,sensor07,sensor08,sensor09,sensor10,sensor11,sensor12,sensor13,sensor14,sensor15,sensor16]
press=[1,1,1,1,1,5,4,4,2,4,4,4,1,5,4]
num_press=0
for steps in range(15) :
sensor[steps]
num_press=press[steps]
for i in range(num_press) :
print(sensor[steps][num_press])
How can I access the value in each sensorXX list which corresponds to the value in press[] list?
For example press[9] is 4, so I want to print sensor10[4] which is V
the reason that i have to go through press[] list is that i have already managed to get some timing functions so i know how much time passed since my last press, so i can either printout the next character inside the specific sensor number list ( e.g sensor01[] or sensor[12] ) and when i reach the maximum number of presses to reloop or i have to move my cursor one place right and start from begin.
i have already build and running in arduino but the code is in C. now i would like to move everything to my raspberry pi 2 and in python.
this was where the first idea came from, and i actually used most of that code to do so in arduino.
youtube video for arduino use of my code
arduino code
I ran your code and got index out of range error. It looks like you just have off by one error. Try this: (Also removed your nested for loop it seems like a mistake)
for steps in range(15) :
sensor[steps]
num_press=press[steps]
print (sensor[steps]) [num_press-1]
Output:
TRANSMITE
READ
DELETE ALL
BACKSPACE
#
Z
O
F
V
L
C
*
S
I
DOOOOONE ! AND THANK YOU ALL FOR YOUR RESPONSE ! :D
sensor16=['1','-','\\','/','*','!']
sensor15=['4','G','H','I']
sensor14=['7','P','Q','R','S']
sensor13=['*']
sensor12=['2','A','B','C']
sensor11=['5','J','K','L']
sensor10=['8','T','U','V']
sensor09=['0',' ']
sensor08=['3','D','E','F']
sensor07=['6','M','N','O']
sensor06=['9','W','X','Y','Z']
sensor05=['#']
sensor04=['BACKSPACE']
sensor03=['DELETE ALL']
sensor02=['READ']
sensor01=['TRANSMITE']
sensor=[sensor01,sensor02,sensor03,sensor04,sensor05,sensor06,sensor07,sensor08,sensor09,sensor10,sensor11,sensor12,sensor13,sensor14,sensor15,sensor16]
press=[1,1,1,1,1,5,4,4,2,4,4,4,1,5,4]
num_press=0
steps=0
for steps in range (15):
for i in range (press[steps]):
print (sensor[steps][i])
and it goes to every value individually.
again ! thanks a lot ....

Learn Python the Hard Way Ex.41 Confused About For loop

I am having trouble understanding how one of the for loops works in Learn Python the Hard Way ex.41. http://learnpythonthehardway.org/book/ex41.html Below is the code from the lesson.
The loop that I am confused about is for i in range(0, snippet.count("###")):
Is it iterating over a range of 0 to snippet (of which there are 6 snippet), and adding the extra value of the count of "###"? So for the next line of code param_count = random.randint(1,3) the extra value of "###" is applied? Or am I way off!?
Cheers
Darren
import random
from urllib import urlopen
import sys
WORD_URL = "http://learncodethehardway.org/words.txt"
WORDS = []
PHRASES = {
"class %%%(%%%):":
"Make a class named %%% that is-a %%%.",
"class %%%(object):\n\tdef __init__(self, ***)" :
"class %%% has-a __init__ that takes self and *** parameters.",
"class %%%(object):\n\tdef ***(self, ###)":
"class %%% has-a function named *** that takes self and ### parameters.",
"*** = %%%()":
"Set *** to an instance of class %%%.",
"***.***(###)":
"From *** get the *** function, and call it with parameters self, ###.",
"***.*** = '***'":
"From *** get the *** attribute and set it to '***'."
}
# do they want to drill phrases first
PHRASE_FIRST = False
if len(sys.argv) == 2 and sys.argv[1] == "english":
PHRASE_FIRST = True
# load up the words from the website
for word in urlopen(WORD_URL).readlines():
WORDS.append(word.strip())
def convert(snippet, phrase):
class_names = [w.capitalize() for w in
random.sample(WORDS, snippet.count("%%%"))]
other_names = random.sample(WORDS, snippet.count("***"))
results = []
param_names = []
for i in range(0, snippet.count("###")):
param_count = random.randint(1,3)
param_names.append(', '.join(random.sample(WORDS, param_count)))
for sentence in snippet, phrase:
result = sentence[:]
# fake class names
for word in class_names:
result = result.replace("%%%", word, 1)
# fake other names
for word in other_names:
result = result.replace("***", word, 1)
# fake parameter lists
for word in param_names:
result = result.replace("###", word, 1)
results.append(result)
return results
# keep going until they hit CTRL-D
try:
while True:
snippets = PHRASES.keys()
random.shuffle(snippets)
for snippet in snippets:
phrase = PHRASES[snippet]
question, answer = convert(snippet, phrase)
if PHRASE_FIRST:
question, answer = answer, question
print question
raw_input("> ")
print "ANSWER: %s\n\n" % answer
except EOFError:
print "\nBye"
snippet.count("###") returns the number of times "###" appears in snippet.
If "###" appears 6 times, then the for-loop iterates from 0 to 6.
"try except" block runs the program until the user hits ^ D.
"While True" loop inside "try" stores list of keys from PHRASES dictonary into snippets. The order of keys is different each time (because of shuffle method). "for loop" inside that "While loop" is to go through each snippet and call convert method on key and value of that snippet.
All "convert method" does it to replace %%%, ***, and ### of that key and value with a random word from the url list of words and return a list (results) consists of two strings: one made from the key and one made from the value.
Then the program prints one of the strings as a question, then gets user input (using raw_input("> ")), but no matter what the user entered, it prints the other returned string as the answer.
Inside convert method, we have three different lists : class_names, other_names, and param_names.
To make class_names, the program counts the number of %%% isnide that key (or value, but they are the same numbers of %%% in them anyways). class_names will be a random list of words in the size of the count of %%%.
other_names is a random list of words again. How many words? in the number of *** found in key (or value, does not matter which one because it is the same in any pairs of them)
param_names is a list of strings in the size of the number of ### found. Each string consists of one, two or three different words seperated by ,.
'result' is a string. The program goes over the three lists (class_names, param_names and other_names), and replace something in result string with what it already made ready for it. Then append this into results list. The (for sentence in snippet, phrase:) loop runs two times because 'snippet' and 'phrase' are two different strings. So, 'result' string is being made two times (one for question one for answer).
I put one part of this program to a smaller sub program to clarify how a list of a certain size from random words in the url is created:
https://github.com/MahshidZ/python-recepies/blob/master/random_word_set.py
Finally, I suggest to put print statements any where in code that you need to understand better. An an example, for this code I printed a number of variables to get exactly what is going on. This is a good way of debugging without a debugger: (look for the boolean variable DEBUG in my code)
DEBUG = 1
if DEBUG:
print "snippet: " , snippet
print "phrase: ", phrase
print "class names: ", class_names
print "other names: " , other_names
print "param names: ", param_names

Compare each item in a list with all previous items, print only unique items

I am using the following regexp to match all occurrences of a special kind of number:
^([0-57-9]|E)[12][0-9]{3}[A-Z]?[A-Z]([0-9]{3}|[0-9]{4})
Let's assume that this regex matches the following five numbers:
31971R0974
11957E075
31971R0974-A01P2
31971R0974-A05
51992PC0405
These matches are then printed using the following code. This prints each item in the list and if the item contains a dash, everything after the dash is discarded.
def number_function():
for x in range(0, 10):
print("Number", number_variable[x].split('-', 1)[0])
However, this would print five lines where lines 1, 3 and 4 would be the same.
I need your help to write a script which compares each item with all previous items and only prints the item if it does not already exist.
So, the desired output would be the following three lines:
31971R0974
11957E075
51992PC0405
EDIT 2:
I solved it! I just needed to do some moving around. Here's the finished product:
def instrument_function():
desired = set()
for x in range(0, 50):
try:
instruments_celex[x]
except IndexError:
pass
else:
before_dash = instruments_celex[x].split('-', 1)[0]
desired.add(before_dash)
for x in desired:
print("Cited instrument", x)
I've done practically no python up until now, but this might do what you're after
def number_function():
desired = set()
for x in range(0, 10):
before_hyphen = number_variable[x].split('-', 1)[0]
desired.add(before_hyphen)
for x in desired:
print("Number", x)
Here is a version of your "finished" function that is more reaonable.
# Don't use instruments_celex as a global variable, that's terrible.
# Pass it in to the function instead:
def instrument_function(instruments_celex):
unique = set()
# In Python you don't need an integer loop variable. This is not Java.
# Just loop over the list:
for entry in instruments_celex:
unique.add(entry.split('-', 1)[0])
for entry in unique:
print("Cited instrument", entry)
You can also make use of generator expressions to make this shorter:
def instrument_function(instruments_celex): 
unique = set(entry.split('-', 1)[0] for entry in instruments_celex)
for entry in set:
print("Cited instrument", entry)
That's it. It's so simple in fact that I wouldn't make a separate function of it unless I do it at least two times in the program.