Ignorieren Sie Fall, Zeichensetzung und Whitespace in Saiten
Frage
Was ist die effizienteste Art, Fall, Zeichensetzung und Whitespace in Saiten zu ignorieren? Diese Saiten sollten in Wörter anstelle von Zeichen unterteilt werden, sollten die oben genannten Details zu Vergleiche ignorieren, und die Scheiben dieser Wortschläge sollten unter Berücksichtigung der Geschwindigkeit so effizient wie möglich sein.
Ich wollte für den folgenden Code in den folgenden Code eingesetzt und untersucht, aber nachdem ich festgestellt hatte, wie lange es dauern würde, um zu bewerten class Slice: def __eq__(self, other): return self.root == other.root
, Ich habe beschlossen, mit zu arbeiten data = tuple(string.split())
stattdessen. Die Säden, die unempfindlich gegenüber Fall, Interpunktion und Abstand sind und die über Wörter anstelle von Charakteren arbeiten, war zu teuer in den rechnerisch teuren Algorithmen, die bereits im folgenden Code ausgedrückt wurden.
class Slice:
def __init__(self, data, offset, length):
self.prefix = data[:offset]
self.root = data[offset:offset+length]
self.suffix = data[offset+length:]
def __eq__(self, other):
return self.root == other.root
def __len__(self):
return len(self.root)
################################################################################
class Match:
def __init__(self, data, key, prefix_tree, suffix_tree):
self.data = data
self.key = key
self.prefix_tree = prefix_tree
self.suffix_tree = suffix_tree
self.__value = len(key) + prefix_tree.value() + suffix_tree.value()
def value(self):
return self.__value
################################################################################
class Tree(tuple):
def __new__(cls, nodes):
tree = super().__new__(cls, nodes)
tree.__value = max(map(Match.value, tree)) if tree else 0
return tree
def value(self):
return self.__value
def find(self, value):
for index, match in enumerate(self):
if match.value() == value:
return index
raise ValueError()
################################################################################
def search(data, key):
length = 0
nodes = []
for d_block in shrink(data, len(key)):
block_len = len(d_block)
if length > block_len:
return Tree(nodes)
for k_block in slide(key, block_len):
if d_block == k_block:
length = block_len
prefix_tree = search(d_block.prefix, k_block.prefix)
suffix_tree = search(d_block.suffix, k_block.suffix)
match = Match(d_block, k_block, prefix_tree, suffix_tree)
nodes.append(match)
return Tree(nodes)
def shrink(data, max_len):
for length in range(min(len(data), max_len), 0, -1):
for block in slide(data, length):
yield block
def slide(data, length):
for offset in range(len(data) - length + 1):
yield Slice(data, offset, length)
################################################################################
def build_tree(nodes):
match = nodes[nodes.find(nodes.value())]
node = match.key
if match.prefix_tree:
node.prefix = build_tree(match.prefix_tree)
if match.suffix_tree:
node.suffix = build_tree(match.suffix_tree)
return node
def flatten_tree(node):
array = [0]
_flatten(node, array)
return tuple(array)
def _flatten(node, array):
if isinstance(node.prefix, Slice):
_flatten(node.prefix, array)
else:
array.append(node.prefix)
array[0] += 1
array.append((array[0], node.root))
if isinstance(node.suffix, Slice):
_flatten(node.suffix, array)
else:
array.append(node.suffix)
Lösung
"Was ist der beste Weg, um dieses Problem zu beheben?"
Das Beste - und nur - ist zu definieren, was dieses Objekt "bedeutet" und was die Länge dieses Objekts "bedeutet".
Das Objekt scheint eine Liste von Wörtern zu sein. Nichts mehr. Das scheint der Wert in zu sein _string
.
Es ist nicht klar was _simple
IS, außer einer unzugänglichen gefilterten Teilmenge der Wörter in _string
.
Also, was ist die Länge? Die Länge der Wörter oder die Länge der Wörter in der gefilterten Teilmenge?
Nur Sie können definieren, was diese Klasse meint. Das Bedeutung bestimmt dann, wie man implementiert __len__
. Bis Sie die Bedeutung definieren, ist es unmöglich zu bestimmen, wie etwas implementiert werden sollte.
Andere Tipps
Wenn Sie eine Iteration auf einer String -Instanz sein möchten, um sich auf seine zu iterieren self.__string
, wie dein __iter__
Die Methode zeigt an, dass die einzige sinnvolle Wahl für die Länge auch die Länge von zurückgibt __string
-- es wäre wirklich eigenartig, wenn len(x)
und sum(1 for _ in x)
führte zu unterschiedlichen Werten.
Ich muss zugeben, ich verstehe den Zweck dieser Klasse nicht __simple
), aber interne Konsistenz ist sowieso wichtig. Also ändern sich entweder __iter__
, oder machen __len__
Logisch kompatibel damit.
Ihre Schnittlogik entgeht mir auch völlig - warum bauen Sie die Slice auf __simple
Auf eine Weise, die sich wahrscheinlich von dem unterscheid __string
? ZB, wenn self.__string
ist '? Boh!' und deshalb self.__simple
ist 'boh', warum würdest du? wollen self[1:-1]
Ein ... Haben __string
von 'boh' aber mit einem __simple
von 'o', so inkompatibel, anders und inkonsistent von der __simple
Sie würden es durch die Neuzunahme aus der Scheibe bekommen ...?
Ich denke, das ist nicht für dieses Q über Länge, aber ich bin nur neugierig auf diese vielen, extrem merkwürdigen Designentscheidungen, die Sie treffen ...