-1

This is in Python.

I want to write a simple Markov-Chain thingy in about 75 lines of code on my Calculator. the only Module im able to import is "Random" and "Math".

heres a quick copy i made, should work in the python terminal, where it is supposed to work.
thats the only way my calculator will have it.

from random import *

class word:
    def __init__(self,word,words):
        self.word=word
        self.words=words.split()

    def addWord(self,word):
        self.words.append(word)

# "x" is an empty list, otherwise contains all previous word-objects
# "s" is the string to use for training
def train(x,s):
    s=s.split()
    if len(x)==0:
        x=[]
    for i in range(len(s)-1):
        if s[i]==s[-1]:
            return x
    w=word(s[i],s[i+1])
    ind=0
    # ///
    # This is the problem area
    for wr in x:
        ind+=1
        if wr in x:
            wr.addWord(s[i+1])
        elif wr not in x:
            x.append(w)
    # ///
    return x

def chain(start, x):
    for i in range(10):
        for w in x:
            if w.word==start[-1]:
                start.append(choice(w.words))
    return start

I want the train function to return a list of "word"-objects, instead:

        if wr in x:
            wr.addWord(s[i+1])
        elif wr not in x:
            x.append(w)

seems to never be executed, im going to keep looking into this since there is surely a solution.

TL:DR; How do i check if an Object is in a list of Objects and if it is, add something to this object, and if it isnt add the object to the list?

if you need more infos, you are free to ask.

Append this to the code if you want to test it:

x=[]
x=train(x, "This is a String")
x=train(x, "And this is yet another Sentence")
y=chain(x, "This")
print(y)

where x is the dictionary of all words in the end and y is the generated sentence.

i expect a sentence which wasnt trained to be generated, using the words and context it was given. context and words coming from the sentences it was trained on.

y might for example be "This is yes another Sentence" which would be a combination of the Strings it got, but isnt equal to either of them.

  • Hi, you have errors in your code. overcheck the logic? are you new to programming/python? – The.B Jan 27 '21 at 10:50
  • What you've show is exactly how to do that. What you haven't described is how you expect that to work. Your `word` object, as implemented, will simply test for *identity*, but I presume, you have some other semantics in mind? – juanpa.arrivillaga Jan 27 '21 at 10:52
  • Well im not new per sé, ive been coding python for 2 years now, but this is just a quick and dirty copy from my calculator, i will look into it and fix it. – Arthur Blitz Jan 27 '21 at 10:53
  • Quite an easy way: use `set` instead of `list` and always do the add. – guidot Jan 27 '21 at 10:58
  • @guidot that actually is a very good tip, i hadnt thought of it. – Arthur Blitz Jan 27 '21 at 11:01
  • though now that i think about i may want to use a dictionary instead of a set, so that i dont need to iterate through the entire thing. – Arthur Blitz Jan 27 '21 at 11:03

2 Answers2

0

Figured it out, thanks guidot.

a dictionary fixes all my problems, since it doesnt allow duplicates and i can simply search for a word through the word itself, perfect for me.

words={
        "if": Word("if","they")
    }
try:
    words[word].addword(wordAfter)
except:
    words[word]=Word(word,wordAfter)

this should do what i want it to do, right?

just need to rewrite my code.

// DONE it works now!

heres the full code:

from random import *


class Word:
    def __init__(self, word, words):
        self.word = word
        self.words = words.split()

    def addword(self, newword):
        self.words.append(newword)


def train(x, s):
    s = s.casefold().split()
    if len(x) == 0:
        x = {}
    for i in range(len(s) - 1):
        if s[i] == s[-1]:
            return x
        try:
            x[s[i]].addword(s[i + 1])
        except:
            x[s[i]] = Word(s[i], s[i + 1])
    return x


def chain(x, start):
    for i in range(100):
        try:
            w = x[start[-1]]
            start.append(choice(w.words))
        except:
            continue
    return start


x = []

trainingStrings = [
    "is this another training string",
    "this is another string of training",
    "training of string is important",
    "the training of this string is important",
    "important is what this string is",
    "is this string important or can is it training",
    "it is a string for training a string"
     "important this is this important is",
     "this is is important this is",
]

for i in trainingStrings:
    x = train(x, i)

for i in range(10):
    y = chain(x, ["this"])
    print(" ".join(y))

thanks especially to guidot.

0

Expanded earlier comment:

Quite an easy way: use set instead of list and always do the add.

If I understood the reply to my comment correctly, a defaultdict using set for value may be the way to go, the key being the last letter of the word. (I have to guess, because there is no caller of chain in the sample code.)

guidot
  • 5,095
  • 2
  • 25
  • 37
  • As i stated in the question, all methods need to be called manually since i am running it on a calculator which only does "from main import *" you can do this aswell in CMD. the key is not the last letter of the word, the key is the word itself. heres an example: The String (as a sentence) gets split: ["This", "Is", "a", "Sentence"] from " This Is a Sentence" so "This" for example would build this in a dictionary: "This": Word("This", "Is") theoretically i could also forego the Word Class altogether. "This": ["Is", "Other-Words"] – Arthur Blitz Jan 27 '21 at 11:24