NoPaste

garten-subtraktiv.py

von chrbr
SNIPPET_DESC:
garten-subtraktiv.py
SNIPPET_CREATION_TIME:
11.05.2023 19:28:01
SNIPPET_PRUNE_TIME:
Unendlich

SNIPPET_TEXT:
  1. #!/usr/bin/env python3
  2.  
  3. #======================================================================
  4. # Basierend auf der Arbeit von Huo
  5. # Der Graphentheorethische Teil ist per Hand gemacht.
  6. # Beginnend mit der Hauptpflanze werden zusätzliche Pflanzen
  7. # hinzu gefügt. Bei Unverträglichkeit wird diese Gruppe verworfen.
  8. # Ansonsten wird weiter gemacht bis man in keiner der Gruppen noch
  9. # eine Pflanze hinzufügen kann.
  10. #
  11. # Gute und schlechte Pflanzennachbarn müssen in zwei getrennten csv-Dateien
  12. # friends.csv und enemies.csv
  13. # in der Form PFLANZE1,PFLANZE2 hinterlegt sein (ein Paar pro Zeile)
  14. #
  15. # Die Pfade in den Zeilen 24 und 25 sind bei Bedarf anzupassen!
  16. #
  17. # Aufruf:
  18. #     garten_dazu.py HAUPTPFLANZE
  19. # wobei HAUPTPFLANZE ein einzelner Name aus der Datei friends.csv ist
  20. #======================================================================
  21.  
  22. import csv
  23. import itertools
  24. import os
  25. import sys
  26.  
  27. # Einlesen der beiden csv-Dateien (Pfade bei Bedarf anpassen!) als Listen zwei-elementiger Mengen
  28. friends = list(set(line) for line in csv.reader(open(os.path.expanduser("./friends.csv"))))
  29. enemies = list(set(line) for line in csv.reader(open(os.path.expanduser("./enemies.csv"))))
  30.  
  31. # Plausibilitätsprüfung der Listen auf widersprüchliche Nachbarbeziehungen
  32. if [s for s in friends if s in enemies] != []:
  33.     print("Pflanzenpaar darf nicht zugleich in friends.csv und enemies.csv liegen")
  34.     print("Dubletten:", [s for s in friends if s in enemies])
  35.     sys.exit(1)
  36.  
  37. # Check Parameter
  38. if not [i for i in friends if sys.argv[-1] in i] or len(sys.argv) != 2:
  39.     print("Script muss mit einer Einzelpflanze aus friends.csv als einzigem Parameter aufgerufen werden!")
  40.     sys.exit(1)    # Abbruch bei Aufruf ohne Parameter oder mit falschem Parameter
  41.  
  42. hauptpflanze = sys.argv[1]
  43.  
  44. # Gute Nachbarn der Hauptpflanze (Liste der Paare {Hauptpflanze, Guter Nachbar})
  45. friends_h = list(s for s in friends if hauptpflanze in s)
  46.  
  47. # Menge der guten Nachbarn der Hauptpflanze
  48. fh = set().union(*friends_h)
  49.  
  50. # Kombinationen dieser guten Nachbarn als Liste zwei-elementiger Mengen
  51. fc = list(set(s) for s in itertools.combinations(fh, 2))
  52.  
  53. # darunter schlechte Nachbarn
  54. enemies_c = list(frozenset(s) for s in fc if s in enemies)
  55.  
  56. # Typen
  57. # friends   <class 'list'>
  58. # enemies   <class 'list'>
  59. # enemies_c <class 'list'>
  60. # friends_h <class 'list'>
  61. # fc        <class 'list'>
  62. # fh        <class 'set'>
  63.  
  64. # Ausgabe der Guten Nachbarn der Hauptpflanze
  65. print ("-------------------------------------")
  66. print ("Gute Nachbarn von", hauptpflanze, ":")
  67. fh_d = fh
  68. fh_d.discard(hauptpflanze)
  69. print (*sorted(fh_d), sep=", ")
  70. print ()
  71.  
  72. # Ausgabe der Paare schlechter Nachbarn:
  73. ltmp = []
  74. for item in enemies_c:
  75.     ltmp.append(sorted(item))
  76. #ltmp.sort()
  77. print ("Darunter harmonieren nicht:")
  78. print (*sorted(ltmp), sep="\n")
  79. print ()
  80.  
  81. # Schleife über Gruppen von Pflanzen. Es wird mit der Liste
  82. # mit einem sets der Hauptfrucht und alles Friends angefangen.
  83. sgroups = set()
  84. fh.add(hauptpflanze)
  85. sgroups.add(frozenset(fh))
  86.  
  87. while enemies_c:
  88.     newgroups = set()
  89.     senemie = enemies_c.pop(0)
  90.     for group in sgroups:
  91.         # Falls die if Abfrage true ergibt ist es ein Konflikt.
  92.         # Dann werden group ohne enemie1 und group ohne enemie2
  93.         # an newgroups angehängt.
  94.         # Falls es kein Konfliktfall gibt wird nur groups kopiert.
  95.         if senemie.issubset(group):
  96.             for enemie in senemie:
  97.                 stmp = set(group)
  98.                 stmp.discard(enemie)
  99.                 newgroups.add(frozenset(stmp))
  100.         else:
  101.             newgroups.add(group)
  102.     sgroups = newgroups.copy()
  103.  
  104. minlen = len(fh)
  105. maxlen = 0
  106. for i in sgroups:
  107.     minlen = min(minlen, len(i))
  108.     maxlen = max(maxlen, len(i))
  109.  
  110. # Erzeuge eine neue Liste aus Elementen mit der kleinsten Anzahl von Pflanzen.
  111. # Entferne diese Gruppen kleinster Länge aus dem Set aller Gruppen.
  112. # Für die Kandidaten aus der Gruppe kleinster Länge überprüfe,
  113. # ob die Kandidaten eine Teilmenge der grösseren Gruppen sind.
  114. # Die Kandidaten, die keine Teilmenge einer der grösseren Gruppen sind
  115. # sind Element einer Clique und nicht erweiterbar.
  116. # Die anderen Kandidaten werden nicht weiter behandelt, weil sie
  117. # Teilmenge einer grösseren Menge sind.
  118. sreduced = set()
  119. while minlen < maxlen:
  120.     lmin = [group for group in sgroups if len(group) == minlen]
  121.     sgroups = sgroups.difference(lmin)
  122.     while len(lmin) > 0:
  123.         kandidat = lmin.pop()
  124.         if not [group for group in sgroups if kandidat.issubset(group)]:
  125.             sreduced.add(kandidat)
  126.     minlen = minlen+1
  127.  
  128. # Die längsten Gruppen werden nicht in einer Schleife untersucht,
  129. # weil es dazu keine grösseren Gruppen gibt, deren Teilmenge sie
  130. # sein könnten. Sie werden als nicht erweiterbare Elemente einer
  131. # Clique einfach angehängt.
  132. sreduced.update(sgroups)
  133. lreduced = []
  134. for group in sreduced:
  135.     lreduced.append(sorted(group))
  136. lreduced.sort()
  137.  
  138. print ("Mögliche Mischkulturen:")
  139. print(*sorted(lreduced, key=len), sep='\n')

Quellcode

Hier kannst du den Code kopieren und ihn in deinen bevorzugten Editor einfügen. PASTEBIN_DOWNLOAD_SNIPPET_EXPLAIN