ubuntuusers.de

[Python3] - Datei sortieren (4 Spalte reverse und Spalte 1-3 normal)

Status: Gelöst | Ubuntu-Version: Ubuntu 16.04 (Xenial Xerus)
Antworten |

halloICKEbins

Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

Mahlzeit,

habe mal wieder das nachfolgende Problem... ich möchte meine Datei mit dem nachfolgenden Schema sortieren und zwar zuerst die 4 Spalte - reverse und dannach Spalte 1-3 "normal"

IP1 IP2 COUNT1 COUNT2
...

Ich würde sorted benutzen aber wie kann ich ihm die Spalten sagen?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
f = open(output,'w')

lines = open(input, 'r').readlines()
lines_set = set(lines)

for line in sorted(lines_set, reverse = True):
  line = line.rstrip()
  print(line, file = f)

f.close()

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4702

Wohnort: Berlin

@halloICKEbins: Das kann man über das key-Argument regeln und dort eine Funktion übergeben die beispielsweise so aussieht: lambda row: (-row[3], row[:3]). Wobei das jetzt davon ausgeht da bei row[3] eine Zahl steht, die mit - negiert werden kann. Das reverse=True muss dann natürlich raus.

halloICKEbins

(Themenstarter)
Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

Mit for line in sorted(lines_set,key=lambda row: (-row[3], row[:3])): bekomme ich immer

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in <lambda>
TypeError: bad operand type for unary -: 'str'

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4702

Wohnort: Berlin

Um noch mal aus meinem letzten Beitrag zu zitieren: „Wobei das jetzt davon ausgeht da bei row[3] eine Zahl steht, die mit - negiert werden kann.“. Es muss halt schon eine Zahl sein. Und da Du die mit „COUNT“ beschrieben hattest, ging ich halt davon aus, dass es eine Zahl ist. Und ich hatte das auch extra erwähnt weil das in Deinem gezeigten Code als Zeichenkette eingelesen wird. Das andere „COUNT“ muss auch umgewandelt werden, wenn es als Zahl sortiert werden soll.

Wobei ich gerade sehe, das in dem Code auch überhaupt keine Zeilen in Spalten aufgetrennt werden, was Du ja auch noch machen musst.

halloICKEbins

(Themenstarter)
Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

COUNT1 und COUNT2 sind nur Zahlen...aber der Fehler liegt wahrscheinlich in der Aufspaltung.

Ich hätte gedacht, dass lambda row: (-row[3], row[:3]) die Zeilen automatisch aufspaltet und ich dann nur die line ausgeben muss!?

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4702

Wohnort: Berlin

@halloICKEbins: Wieso sollte das die Zeile aufspalten und vor allem wie? Das ist Python und nicht AWK. Du musst die Zeilen aufspalten und die Werte die anders als lexikographisch sortiert werden sollen auch in die entsprechenden Datentypen umwandeln.

halloICKEbins

(Themenstarter)
Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

Habe es jetzt wie folgt gelöst:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def sortier_helfer(item):
    z = item[3]
    z2 = item[0]
    z3 = item[1]
    z4 = item[2]
    return (-int(z), z2, z3, z4)

with open(inputfile) as fin:
    mylist = [[item for item in line.strip().split(' ')] for line in fin]

mylist.sort(key=sortier_helfer)

f = open(outputfile,'w')
for line in mylist:
  print(' '.join(map(str, line)), file = f)

f.close()

Für Anmerkungen bin ich trotzdem empfänglich und dankbar!

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4702

Wohnort: Berlin

@halloICKEbins: Laut Beschreibung hast Du ja zwei COUNT-Spalten. Die andere musst Du zum sortieren auch in eine Zahl wandeln wenn die Sortierung da auch numerisch sein soll. Sonst kommt beispielsweise die 10 vor der 2. Das map(str, line) ist überflüssig weil das schon alles Zeichenketten sind.

mylist ist kein schöner Name und line ist in der zweiten Schleife falsch. rows und row wären besser und üblicher.

Warum wird einmal with mit open() verwendet, beim zweiten mal dann aber nicht?

halloICKEbins

(Themenstarter)
Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

Liegt an den verschiedenen Codesnipseln ☹ ... muss ich noch einheitlich schreiben.

Das mit COUNT1 konnte ich noch nicht ganz lösen, da ich festgestellt habe, dass dort auch Wörter vorkommen können ... Mir ist schon aufgefallen, dass er es nicht richtig sortiert aber für den ersten Moment ging es so ... bis jetzt habe ich auch noch keine Lösung dafür.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4702

Wohnort: Berlin

Ungetestet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
from functools import total_ordering

DELIMITER = ' '


@total_ordering
class ReverseOrder(object):
    
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return self.value == other.value
    
    def __lt__(self, other):
        return other.value < self.value


def convert_count(string):
    try:
        count = int(string)
    except ValueError:
        return (float('inf'), string)
    else:
        return (count, '')


def create_key(row):
    return (
        ReverseOrder(convert_count(row[3])),
        row[0],
        row[1],
        convert_count(row[2]),
    )


def main():
    with open('test.txt') as in_file:
        rows = sorted(
            (line.strip().split(DELIMITER) for line in in_file), key=create_key
        )
    with open('test2.txt', 'w') as out_file:
        out_file.writelines(DELIMITER.join(row) + '\n' for row in rows)


if __name__ == '__main__':
    main()

convert_count() ist so gestaltet, dass Zeichenketten nach Zahlen sortiert werden. Wenn das umgekehrt sein soll, müsste man in dem Tupel mit den Zeichenketten -∞ verwenden.

halloICKEbins

(Themenstarter)
Avatar von halloICKEbins

Anmeldungsdatum:
12. September 2017

Beiträge: 226

Funktioniert vorzüglich .. Danke

Antworten |