Zähle Einträge im Dictionary

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
bernd_1980
User
Beiträge: 5
Registriert: Montag 14. Oktober 2013, 18:06

Hallo Forum,
ich habe folgendes Problem und würde das gerne in Python lösen, eine Möglichkeit das Ganze über eine DB zu spielen habe ich schon.

Ich habe mir ein File erstellt, worin die Einträge so aussehen:

a, j, n
a, n, n
a, n, n
a, n, t
a, n, j
b, n, n
.
.
.

Jetzt sollte die erste Spalte zusammengefasst werden und alle j, n oder t für die erste Spalte gezählt werden.
Das Endergebnis sollte also so aussehen: a: j=4, n=3, t=1

Ich dachte mir, dass man das vll. über dictionary(s) in Python leicht lösen könnte.

Die 3te und umständliche Art und Weise wäre jede Spalte einer Zeile einzulesen und mit der nächsten zu vergleichen und dann die Spalten 2 und 3 aufzuaddieren.

Gibt es eine Lösung die kürzer ist als meine angedachte?

Danke vielmals für jede Hilfe!
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Hallo und Wilkommen in Forum.

Wenn ich es lösen müsste, würde ich csv.reader() und collections.Counter verwenden.
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@bernd_1980: Grundsätzlich sollte das mit Wörterbüchern beziehungsweise `collections.defaultdict()` gehen. Praktisch ist mir jetzt nicht ganz klar wie bei den gezeigten Eingabedaten das gezeigte Ergebnis herauskommen soll.
bernd_1980
User
Beiträge: 5
Registriert: Montag 14. Oktober 2013, 18:06

Hallo,

danke schon einmal für Eure Hilfe.

Wie ich gerade gesehen habe, habe ich mich ein wenig vertan

Also angenommen die Einträge sehen so aus:

a, j, n
a, n, n
a, n, n

Dann sollte das Ergebnis so aufgeschlüsselt werden:

a: Spalte 1: j=1, n=2
a: Spalte 2: j=0, n=3

Wäre das mit collections.Counter() möglich zu lösen?

@pillmuncher: Danke Dir vielmals für den Input, war leider schon mit meinen Gedanken einen Schritt weiter ...
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo bernd_1980,

was hast Du bisher schon versucht?
BlackJack

@bernd_1980: Ist die erste Spalte bereits gruppiert und ist das garantiert? Also stehen immer alle Zeilen mit dem gleichen Wert in der ersten Spalte in einem Block, oder sind die zufällig(er) verteilt?
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal ein erster Ansatz:

Code: Alles auswählen

#!/usr/bin/env python2
from collections import Counter

DATA = """\
a, j, n
a, n, n
a, n, n
a, n, t
a, n, j
b, n, n"""


def get_rowcounters(data):
    lines = [line.split(', ') for line in data.split('\n')]
    return [Counter(row) for row in zip(*lines)[1:]]


def pretty_print(rowcounters):
    for i, counter in enumerate(rowcounters, 1):
        print 'Row #{}:'.format(i)
        for key, value in sorted(counter.items()):
            print '  {}: {}'.format(key, value)


def main():
    counters = get_rowcounters(DATA)
    pretty_print(counters)


if __name__ == '__main__':
    main()
Bedarfsweise kann man natürlich an einigen Stellen auch Generatoren und `itertools`-Konstrukte einsetzen. Liest sich dann IMHO nur etwas schlechter.
Zuletzt geändert von snafu am Montag 14. Oktober 2013, 20:14, insgesamt 1-mal geändert.
bernd_1980
User
Beiträge: 5
Registriert: Montag 14. Oktober 2013, 18:06

Hallo,
die erste Spalte ist bereits gruppiert und so vorhanden, wie ich sie hier dargestellt habe. Dafür habe ich gesorgt!

Sprich, die erste Spalte enthält immer Einträge in der Form:

a,...,
a,...,
a,...,
b,....,
etc.

Natürlich können noch mehr a`s untereinanderstehen. Ich glaube es sind immer genau 6 a`s, 6 b`s usf.

@Sirius3: Was ich schon versucht habe. Ich lade einfach das File, worin die Daten so aufgelistet sind, wie hier dargestellt in eine DB und groupiere das Ganze dann und gebe noch ein count auf die Einträge.

Das war sozusagen die schnelle Lösung, nur weiss ich nicht, ob ich immer einen DB Zugriff habe, deswegen wollte ich vorsichtshalber das Ganze noch in Python ausprogrammieren.
Ich weiss, dass ich es auch über die Methode:

Vergleiche erste Zeile, erste Spalte mit 2ter Zeile, wenn gleich, dann nimm den Wert aus der zweiten Spalte, merke dir den, vergleiche den Wert mit 2ter Zeile, 2ter Spalte und wenn gleich, dann erhöhe counter um 1.
Also die normaler Vorgehensweise, aber ich denke, dass es noch eine einfachere Möglichkeit in Python geben könnte, nur bin ich dabei leider nicht so bewandert!

@snafu

Danke Dir vielmals für Deine Hilfe.
Da muss ich mir zwar noch viel anschauen bzgl. zip und Counter, aber es ist sicher seine Mühe wert!

Danke Dir vielmals!
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@bernd_1980: Als Basis für deine Implementation könntest du das hier verwenden (Python 3.3):

Code: Alles auswählen

from collections import defaultdict, Counter

data = """
a, j, n
a, n, n
a, n, n
"""
counted = defaultdict(Counter)

for line in data.strip().split('\n'):
    head, *tail = line.split(', ')
    counted[head].update(enumerate(tail))

print(counted)
Ergebnis:

Code: Alles auswählen

defaultdict(<class 'collections.Counter'>, {'a': Counter({(1, 'n'): 3, (0, 'n'): 2, (0, 'j'): 1})})
Wenn du das csv-Modul verwendest, brauchst du kein str.strip() und str.split().

Ergebnisse für Spalten, in denen ein Wert nicht vorkommt, werden vom Code oben weggelassen, statt dass der Wert für die Spalte als 0 mal vorkommend ausgegeben wird. Auch das kann man lösen:

Code: Alles auswählen

>>> from collections import defaultdict, Counter
>>> d = defaultdict(int)
>>> d
defaultdict(<class 'int'>, {})
>>> d['a']
0
>>> d
defaultdict(<class 'int'>, {'a': 0})
>>> c = Counter('b')
>>> c
Counter({'b': 1})
>>> c.update(d)
>>> c
Counter({'b': 1, 'a': 0})
In specifications, Murphy's Law supersedes Ohm's.
Antworten