Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 02:24:59

meine Holzhammermethode:

Code: Alles auswählen

export fund=$(grep "^........$" /usr/share/dict/ngerman | sed "s_^..__" | sed "s_..\$__" | sort  | uniq -c | sort -n | tail -n1 | sed "s_  *_ _"| cut -d " " -f 3); grep "^.."$fund /usr/share/dict/ngerman | grep "^........$" && echo "war wohl: "$fund " (andere treffer ignoriert)"
Ich habs aber nur runtergeschrieben und nichts optimiert ... ich war mehr damit beschäftigt mal zu schauen, ob ich die andere Aufgabe lösen kann. Ich denke, der Autor bezieht sich indirekt auf das Wortproblem, "Simple word problems in universal algebras". Ich würde am ehesten annehmen, er war Student oder jemand der bei den teachning meetings, Sympossien, Konferenzen, etc anwesend war. Steht im Lebenslauf vom Autor, was dass sich mit "The Genesis of Attribute Grammars" in Einklang bringen lässt?

@wanne: Dein egrep bringt bei /usr/share/dict/ngerman 63 sche und 64 chte, mein Code 77 sche

mit awk finde ich ne etwas andere Lösung, aber auch Länge 77

awk.awk:

Code: Alles auswählen

BEGIN {FS = ""
		l1 = 1
		l2 = 1
		oldvorne = ""
		v2 = ""
}
{ 
		vorne = $1 $2 $3 $4
		hinten = $7 $8 $5 $6
		} 

NR==1{ oldvorne = vorne }

{ 
		if (oldvorne == vorne) { liste1[l1++] = hinten; }
		else {
				if (l1 > l2 ){ 
						split("", liste2 ) 
						l2 = 1
	   					for (i in liste1) {liste2[l2++] = liste1[i]}
						v2 = oldvorne
						l1 = 1
						liste1[l1++] = hinten;		
				}
				else {  v1 = ""
						l1 = 1 
						split("", liste1 ) 
						}
				}
		oldvorne = vorne
}

END {	
	   for (i in liste2) {print substr(liste2[i],1,2) " " v2 " " substr(liste2[i],3,2)}
	   print "laenge:" l2 " treffer: " v2
}

Code: Alles auswählen

grep ^........$  /usr/share/dict/ngerman | sed "s_\(^..\)\(.*\)_\2\1_" | sort | awk -f awk.awk
edit: sche 77 kam bei awk raus
Vorteil von Lösung 1: ist einfach nur runtergeschrieben, verschwendete Arbeitszeit gegen null
Vorteil von der awk Lösung: die Datei muss nur einmal gelesen werden, die Anzahl der Arrays bei awk bleibt minimal
aber beides bei dem Spielkram hier nicht weiter wichtig
... und Meillo wird sicher auch wieder was zu meckern finden, was nicht posix passend ist :mrgreen: :THX:

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 07:51:43

Klasse, dass schon so viel Aktivitaet hier ist. :THX:


Ich poste mal ein paar Gedanken, die mir bei den bisherigen Posts kommen:

Code: Alles auswählen

sort | uniq -c | sort -n
Das ist ein typisches Konstrukt, fuer immer dann wenn man wissen will, was am haeufigsten vorkommt. Shell-Loesungen werden das fast immer enthalten.

Wenn mich nur das oder die haeufigsten interessieren, dann wuerde ich in Scripten normalerweise `sort -nr' nehmen (um absteigend zu sortieren) und dann von oben runter nur die ersten paar ausgeben. Das ist einfacher als vom Ende her.


Dieses Konstrukt von inne gefaellt mir sehr gut:

Code: Alles auswählen

awk 'NR==1{most=$1} $1==most{print $0}'
D.h. als Alternative zu `head -n1'.


Wie schon erkannt ist `cut -b' bei Text selten sinnvoll. Richtig ist `cut -c' ... wobei das in vielen Implementierungen auch nur Bytes macht und keine Multibyte-Zeichen versteht (wie es das eigentlich sollte). Das ist je nach Implementierung unterschiedlich. (Als ich die Situation 2015 analysiert habe haben nur die Implementierungen von FreeBSD und den Heirloom-Tools, Multibyte-Characters korrekt unterstuetzt.) Da muss man ein bisschen aufpassen.


Dass in den Wordlists auch ``seltsame'' Woerter (also auch konjungierte Formen und so) drin sind ist fuer unsere Aufgabe etwas unguenstig, aber nunja. Das soll nicht gross stoeren.


Ganz nett ist das `-x' Flag bei grep. Folgende zwei Aufrufe sind aequivalent:

Code: Alles auswählen

grep '^........$'
grep -x '........'

Hier meine Loesung von gestern:

Code: Alles auswählen

sed -n 's/^..\(....\)..$/\1/p' /usr/share/dict/ngerman | sort | uniq -c | sort -nr | cut -c9- | sed q
Straight-forward:
- Mittelteil der 8-buchstabigen Woerter ausgeben
- sortieren
- zaehlen
- nach Haeufigkeit sortieren
- Zahl wegschneiden
- nur den ersten Eintrag

Nun mit innes Code um bei Gleichheit alle gleich haeufigen auszugeben:

Code: Alles auswählen

sed -n 's/^..\(....\)..$/\1/p' /usr/share/dict/ngerman | sort | uniq -c | sort -nr | awk 'NR==1{m=$1} $1==m{print $2}'
(Eigentlich hatte ich statt dem awk am Ende zuerst ja `cut -c9-' stehen, um die Anzahl wegzuschneiden. Aber als ich in POSIX geschaut habe, musste ich feststellen, dass uniq-Implementierungen sich hier nicht an POSIX halten, nachdem die Ausgabe der Form "%d %s" entsprechen sollte und nicht etwa der Form "% 7d %s" (GNU uniq 8.13) oder "% 4d %s" (uniq in FreeBSD).)
Use ed once in a while!

Benutzeravatar
hikaru
Moderator
Beiträge: 13594
Registriert: 09.04.2008 12:48:59

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von hikaru » 07.10.2021 08:52:21

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Wenn mich nur das oder die haeufigsten interessieren, dann wuerde ich in Scripten normalerweise `sort -nr' nehmen (um absteigend zu sortieren) und dann von oben runter nur die ersten paar ausgeben. Das ist einfacher als vom Ende her.
Wir hatten das so ähnlich schon mal in fischigs Systemd-Paketsuch-Thread:
Ob die Sortierung aufsteigend oder absteigend ist halte ich für unerheblich. Die Eine ist genauso leserlich wie das Andere. Sie muss nur klar sein. Wenn dann die zusätzliche Anforderung kommt, die kürzeste Lösung zu liefern, dann ist sort -r | head schlechter als sort | tail.
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Dieses Konstrukt von inne gefaellt mir sehr gut:

Code: Alles auswählen

awk 'NR==1{most=$1} $1==most{print $0}'
D.h. als Alternative zu `head -n1'.
Warum? Es ist deutlich länger und ich meine auch schwerer lesbar als head.
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Ganz nett ist das `-x' Flag bei grep. Folgende zwei Aufrufe sind aequivalent:

Code: Alles auswählen

grep '^........$'
grep -x '........'
-x ist aber länger. ;)
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Straight-forward:
- Mittelteil der 8-buchstabigen Woerter ausgeben
- sortieren
- zaehlen
- nach Haeufigkeit sortieren
- Zahl wegschneiden
- nur den ersten Eintrag
Meine Vermutung war, dass die Eingangswörterliste in diesem Spezialfall bereits sortiert ist, weshalb das erste sort unnötig sein sollte. In der Praxis einsetzen würde ich es trotzdem, aber wen nach der kürzesten Lösung gefragt ist, wird dieses Detail relevant. Offenbar war meine Annahme falsch. Warum?
Ob "Zahl wegschneiden" Teil der Aufgabe ist, war für mich nicht eindeutig.

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 09:56:04

hikaru hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 08:52:21
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Wenn mich nur das oder die haeufigsten interessieren, dann wuerde ich in Scripten normalerweise `sort -nr' nehmen (um absteigend zu sortieren) und dann von oben runter nur die ersten paar ausgeben. Das ist einfacher als vom Ende her.
Wir hatten das so ähnlich schon mal in fischigs Systemd-Paketsuch-Thread:
Ob die Sortierung aufsteigend oder absteigend ist halte ich für unerheblich. Die Eine ist genauso leserlich wie das Andere. Sie muss nur klar sein. Wenn dann die zusätzliche Anforderung kommt, die kürzeste Lösung zu liefern, dann ist sort -r | head schlechter als sort | tail.
Wenn man nicht nur das eine erste haben will, sondern wenn mehrere gleich oft vorkommen, dann geht das nur mit absteigender Sortierung (einfach). Wenn man die Ausgabe weiterverarbeiten will, dann ist es meist sinnvoll, die relevanten Werte zu Beginn zu haben. (Das ist meine Erfahrung.)
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Dieses Konstrukt von inne gefaellt mir sehr gut:

Code: Alles auswählen

awk 'NR==1{most=$1} $1==most{print $0}'
D.h. als Alternative zu `head -n1'.
Warum? Es ist deutlich länger und ich meine auch schwerer lesbar als head.
Es macht etwas anderes, `head -n1' nimmt nur stur die erste Zeile. Der awk-Code nimmt alle Zeilen vom Anfang, bei denen das erste Feld gleich ist, d.h. wenn mehrere gleich haeufig sind, gibt es alle aus.

``Alternative'' war ein schlechter Begriff von mir. Gemeint habe ich, dass man das Konstrukt an die Stelle von `head -n1' setzt. Im Fall von nur einem am oeftesten vorkommenden Mittelteil tut es das Gleiche. Wenn aber mehrere gleich oft vorkommen, verhaelt es sich anders.
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Ganz nett ist das `-x' Flag bei grep. Folgende zwei Aufrufe sind aequivalent:

Code: Alles auswählen

grep '^........$'
grep -x '........'
-x ist aber länger. ;)
Da hast du recht. ;-) ... Ich wollte nur etwas Werbung fuer `grep -x' machen, weil das Flag eher wenig bekannt ist, manchmal aber ganz nett ist. (U.a. kann es fuer Einsteiger einfacher sein als die Zeilenanker.)
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 07:51:43
Straight-forward:
- Mittelteil der 8-buchstabigen Woerter ausgeben
- sortieren
- zaehlen
- nach Haeufigkeit sortieren
- Zahl wegschneiden
- nur den ersten Eintrag
Meine Vermutung war, dass die Eingangswörterliste in diesem Spezialfall bereits sortiert ist, weshalb das erste sort unnötig sein sollte. In der Praxis einsetzen würde ich es trotzdem, aber wen nach der kürzesten Lösung gefragt ist, wird dieses Detail relevant. Offenbar war meine Annahme falsch. Warum?
Es muss deshalb sortiert werden, weil zwar moeglicherweise die Wortliste sortiert war, aber es die Mittelteile damit nicht auch sind. Z.B.:

Code: Alles auswählen

aaxxxxaa
aayyyyaa
bbxxxxbb
Das ergibt dann:

Code: Alles auswählen

xxxx
yyyy
xxxx
Und daraus macht `uniq -c' dann:

Code: Alles auswählen

1 xxxx
1 yyyy
1 xxxx
... wenn man sie nicht nochmal sortiert. Das sort sortiert ja nur die extrahierten Mittelteile und nicht die urspruengliche Wortliste. ;-)

Man kann sich merken, dass vor `uniq' fast immer sortiert werden muss. Jedenfalls ist es in meiner Praxis sehr selten, dass ich davor mal nicht sortieren will.
Ob "Zahl wegschneiden" Teil der Aufgabe ist, war für mich nicht eindeutig.
Es war ja insgesamt sehr offen wie die Ausgabe ueberhaupt aussehen soll. ;-)

Erstmal kann man ja einfach nur den haeufigsten Mittelteil ausgeben. Davon zu den Woerten zu kommen ist nicht allzu schwer (der Mittelteil steckt in $m):

Code: Alles auswählen

grep -x ..$m.. /usr/share/dict/ngerman
Fuer die ganz harten Quoteing-Vermeider und Kurzcode-Schreiber gerne auch so:

Code: Alles auswählen

grep ^..$m..$ /usr/share/dics/ngerman
;-) (Ihr koennt euch ja mal klar machen, warum das so funktioniert.)

Bzw. fuer den Fall mehrerer haeufigster Mittelteile, falls man sie in eine Liste zusammenfassen will, z.B. in dieser Weise:

Code: Alles auswählen

... | sed 's,.*,..&..,' | grep -x -f- /usr/share/dict/ngerman
Use ed once in a while!

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 10:08:23

ich hab grade übrigens noch nen Grund gefunden, der für "Abgabe Sonntagabend" spricht: man kann "live" mitlesen und direkt nachfragen und steht nicht am nächsten Morgen vor drei Seiten unverständlichen Lösungen, bei denen man gar nicht weiß, wo man zuerst fragen soll ... ich nehm einfach mal an, hier lesen mehr Leute gegen 18:00 mit als nachts um 4 :mrgreen:

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 10:33:42

ich hab mich nochmal mit uniq beschäftigt, aber irgendwie passt da was nicht

Code: Alles auswählen

grep "^........$" /usr/share/dict/ngerman | sort -k1.3 | uniq -s 2 -c -w 4 | sort -n
41 bebendem - also 41 bend
kann mir jemand erklären, was ich da übersehe?

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von JTH » 07.10.2021 11:04:17

eggy hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 10:08:23
und steht nicht am nächsten Morgen vor drei Seiten unverständlichen Lösungen
Der letzte Beitrag heute Nacht stammt von einem gewissen „eggy“, da könntest du dich beschweren :P
von eggy » Heute 02:24

Interessant, welche Interpretationen der Aufgabe und Ansätze ihr schon habt :THX:

Ich hab mir als Aufgabe genommen, einfach die gesuchte Teilmenge eines Dictionaries auszugeben, also eine lange Reihe Wörter. (Die Anzahl der Wörter kann man ja immer leicht mit einem angehängten | wc -l bekommen und den ermittelten Wortmittelteil sieht man hoffenlich auf den ersten Blick.) Meine Ausgaben sind also einfach solche:

Code: Alles auswählen

Abscheus
Anschein
[…]
zischend
zischest


Meine erste Lösung ist recht awk-lastig:

Code: Alles auswählen

$ cat max_word_set_same_inner_chars_awk
#!/bin/sh

words=$(awk "length==$1" "$4" | sort -k"1.$2,1.$3")
N=$(($3-$2+1))
echo "$words" | awk "S==substr(\$0, $2, $N)" S="$(echo "$words" | awk '
	{
		s = substr($0, I, N);
		if (s != S) {
			if (L > mL) {
				mL = L;
				mS = S;
			}
			L = 0;
			S = s;
		}
		++L;
	}
	END { print(mS) }' I="$2" N=$N)"
Manche Stellen würde ich da normalerweise ausführlicher schreiben, aber ums kurz zu halten … Flexibel aufzurufen etwa so (die zweite Lösung genauso):

Code: Alles auswählen

$ ./max_word_set_same_inner_chars_awk 8 3 6 /usr/share/dict/ngerman


Lose dem Motto „alles ist eine Datei“ folgend (auch Wortmengen) sieht meine zweite Variante mal etwas anders aus:

Code: Alles auswählen

$ cat max_word_set_same_inner_chars_files 
#!/bin/bash

td=$(mktemp -d) || exit
cd "$td"
I=$(($2-1))
N=$(($3-I))
while read w; do
	[ ${#w} -eq "$1" ] && printf "%s\n" "$w" >>"${w:$I:$N}"
done < "$4"
cat -- "$(wc -l * | sort -nrk1 | awk 'NR==2 {print $2}')"
rm -fr "$td"
Ist leider Bash-spezifisch, da mir $(echo "$w" | cut -c"$2-$3"), statt ${w:$I:$N}, in Schleife dann doch zu langsam war und, wie ihr schon angemerkt habt, anscheinend nicht multibyte-fähig. Eigentlich sollte das eine möglichst reine Shell-Lösung werden, die Subshell in der vorletzten Zeile zum Ermitteln der längsten Datei stört mich da etwas.
Manchmal bekannt als Just (another) Terminal Hacker.

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 11:25:36

JTH hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 11:04:17
Der letzte Beitrag heute Nacht stammt von einem gewissen „eggy“, da könntest du dich beschweren :P
Ja, das ist der allerschlimmste von dieser komischen Scriptingfutzigang :twisted:

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 11:32:41

eggy hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 10:33:42
ich hab mich nochmal mit uniq beschäftigt, aber irgendwie passt da was nicht

Code: Alles auswählen

grep "^........$" /usr/share/dict/ngerman | sort -k1.3 | uniq -s 2 -c -w 4 | sort -n
41 bebendem - also 41 bend
kann mir jemand erklären, was ich da übersehe?
Dein sort stimmt nicht. Es muss so aussehen:

Code: Alles auswählen

sort  -k1.2,1.6
Du sortierst damit im ersten Feld (die Zeile hat eh nur ein Feld) vom 2. bis zum 4. Buchstaben (1-based).

Die Idee mit dem selektiven Sortieren und dem selektiven Uniq finde ich cool! Das schafft es dann tatsaechlich in einem Dateidurchlauf, die Liste der Woerter auszugeben. Man muss die Ausgabe dann nur noch abbrechen wenn sich der Mittelteil zum ersten Mal aendert. Das sollte mit awk kein Problem sein.

Nur fuer den Fall, dass es mehrere gleiche haeufig auftretende Mittelteile gaebe, muesste man etwas mehr awk-Logik hinten anhaengen.
Use ed once in a while!

tobo
Beiträge: 1996
Registriert: 10.12.2008 10:51:41

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von tobo » 07.10.2021 11:33:42

eggy hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 10:33:42
ich hab mich nochmal mit uniq beschäftigt, aber irgendwie passt da was nicht

Code: Alles auswählen

grep "^........$" /usr/share/dict/ngerman | sort -k1.3 | uniq -s 2 -c -w 4 | sort -n
41 bebendem - also 41 bend
kann mir jemand erklären, was ich da übersehe?
Ich denke, dass du die 2 übersprungenen Zeichen zu den Gesamtzeichen hinzuzählen musst. Zumindest kommen hier 77 zusammen:

Code: Alles auswählen

grep "^........$" /usr/share/dict/ngerman | sort -k1.3 | uniq -s 2 -c -w 6 | sort -n | grep " [^ ][^ ]sche"
Zu deinem awk-Code sind mir 2 Sachen aufgefallen: Die Anzahl der Treffer ist eins zu hoch. Aufgefallen ist mir das bei deinem 2 Fehler, den ich nämlich auch gemacht habe. Nämlich wenn der häufigste Treffer am Ende der Datei steht und somit das Dateiende aber nicht die Abfrage stattfindet. Beispieldatei dafür:

Code: Alles auswählen

11aaaa11
22bbbb22
22bbbb22
yyzzzzyy
yyzzzzyy
yyzzzzyy
yyzzzzyy
yyzzzzyy
yyzzzzyy
yyzzzzyy
yyzzzzyy
ergibt:

Code: Alles auswählen

$ grep ^........$  t.txt | sed "s_\(^..\)\(.*\)_\2\1_" | sort | awk -f awk.awk
22 bbbb 22
22 bbbb 22
laenge:3 treffer: bbbb

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 11:46:20

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 11:32:41
Du sortierst damit im ersten Feld (die Zeile hat eh nur ein Feld) vom 2. bis zum 4. Buchstaben (1-based).
mit sort bin ich noch nie gut zurechtgekommen ... coreutils mal wieder :twisted:

total offtopic:
ich hab grad noch was interessantes gefunden: "info tsort", der Teil zum Background ... frag mich, ob man damit nicht auch noch was cooles anstellen könnt

eggy
Beiträge: 3331
Registriert: 10.05.2008 11:23:50

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von eggy » 07.10.2021 11:51:03

@tobo: :THX:
man soll halt nicht mitten in der nacht rumcoden :oops:
mir war der Fehler mit dem letzten Durchlauf schon klar, und dann meinte mein umnachtetes Gehirn "spielt keine Rolle, ob die 77 Treffer oder die anderen 77 Treffer ausgegeben werden" ... dass es zuletzt auch einmal 78 sein könnten, hab ich komplett nicht auf dem Schirm gehabt :facepalm:

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 18:54:37

JTH hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 11:04:17
Meine erste Lösung ist recht awk-lastig:

Code: Alles auswählen

$ cat max_word_set_same_inner_chars_awk
#!/bin/sh

words=$(awk "length==$1" "$4" | sort -k"1.$2,1.$3")
N=$(($3-$2+1))
echo "$words" | awk "S==substr(\$0, $2, $N)" S="$(echo "$words" | awk '
	{
		s = substr($0, I, N);
		if (s != S) {
			if (L > mL) {
				mL = L;
				mS = S;
			}
			L = 0;
			S = s;
		}
		++L;
	}
	END { print(mS) }' I="$2" N=$N)"
Also mir dreht sich schon alles, wenn ich diesen Code lese, und dabei bin ich in awk eigentlich fit. Du scheinst mich herausfordern zu wollen. ;-) ... mal ehrlich, das ist schon harter Code! (Memo an mich: Ich sollte das naechste Mal nichts mehr von kryptischem Code schreiben, sonst steigt unser Terminal-Hacker bloss gleich wieder darauf ein. :-P )

... ich seh' schon wie ich heute mitten in der Nacht aufstehe, weil mich dieser Code nicht schlafen laesst, oder wie ich aus Alptraeumen von awk-Code, den ich nicht verstehe, aufschrecke ... und dann poste ich auch mal zu nachtschlafener Zeit. Waere dann gut, wenn noch jemand da waere, mit dem ich mir die Sache von der Seele reden koennte. :-D

Lose dem Motto „alles ist eine Datei“ folgend (auch Wortmengen) sieht meine zweite Variante mal etwas anders aus:

Code: Alles auswählen

$ cat max_word_set_same_inner_chars_files 
#!/bin/bash

td=$(mktemp -d) || exit
cd "$td"
I=$(($2-1))
N=$(($3-I))
while read w; do
	[ ${#w} -eq "$1" ] && printf "%s\n" "$w" >>"${w:$I:$N}"
done < "$4"
cat -- "$(wc -l * | sort -nrk1 | awk 'NR==2 {print $2}')"
rm -fr "$td"
Das kann ich jetzt wenigstens lesen. ;-) Toll finde ich, dass du so schoen kreative Ansaetze gewaehlt hast, waehrend wir anderen so straight-forward rangegangen sind.

Zwei technische Anmerkungen zu deinem Shellscript:

1) Loeschen von Temp-Dirs. Wenn man ein Temp-Dir am Anfang erzeugt und am Ende loescht, dann kann man im Script zwischendurch nicht aussteigen, sondern braucht dann eine Cleanup-Funktion, usw. Dabei gibt es einen so eleganten Weg mit Traps, um das Temp-Dir automatisch aufraeumen zu lassen:

Code: Alles auswählen

td=$(mktemp -d) || exit
trap 'rm -rf "$td"' 0 1 2 15
Damit wird es beim Ende des Scripts automatisch geloescht, sowohl bei einem normalen Ende (mit `exit') als auch beim Abbruch mit ^C. Will man Abbrechen, um das Tempdir anzuschauen, dann kann man ^\ verwenden (das ist SIGQUIT, womit man auch Coredumps erzeugen kann).

Schoen daran ist, dass damit das Loeschen des Temp-Dirs an der gleichen Stelle im Code ist wie das Erzeugen.

2) `sort -k1'. Soweit ich weiss ist `-k1' nicht anders als wenn man es ganz weglaesst. `-k' ist 1-basiert in der Nummerierung, d.h. es wird ab dem ersten Feld (bis zum Ende der Zeile!) sortiert. Das ist aber auch das was ohne `-k' passiert, naemlich die ganze Zeile. Das vergisst man oft: Will man *nur* nach dem ersten Feld sortieren, dann muss man `-k1,1' schreiben ... was hier aber keinen Unterschied macht.
Use ed once in a while!

tobo
Beiträge: 1996
Registriert: 10.12.2008 10:51:41

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von tobo » 07.10.2021 19:16:31

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 11:32:41
Dein sort stimmt nicht. Es muss so aussehen:

Code: Alles auswählen

sort  -k1.2,1.6
Bist du da sicher? Es soll sortiert werden ab Buchstabe 3ff.

Code: Alles auswählen

$ printf "aabbbbcc\nbbaaaacc\nccaaaabb\nabbbbcca\nbaaaaccb\ncbbbbaac\n" | sort -k1.2,1.6
baaaaccb
aabbbbcc
bbaaaacc
cbbbbaac
abbbbcca
ccaaaabb
$ printf "aabbbbcc\nbbaaaacc\nccaaaabb\nabbbbcca\nbaaaaccb\ncbbbbaac\n" | sort -k1.3
ccaaaabb
bbaaaacc
baaaaccb
cbbbbaac
aabbbbcc
abbbbcca

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 19:24:19

tobo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:16:31
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 11:32:41
Dein sort stimmt nicht. Es muss so aussehen:

Code: Alles auswählen

sort  -k1.2,1.6
Bist du da sicher? Es soll sortiert werden ab Buchstabe 3ff.
:oops: Du hast recht. :THX: Jetzt bin ich selber schon ganz mit dem 0-basiert und 1-basiert durcheinander gekommen. ;-)

So waere es richtig (denke ich):

Code: Alles auswählen

sort -k1.3,1.6
Wobei es egal ist, ob wir den Rest hinten mitsortieren oder nicht.
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von JTH » 07.10.2021 20:02:54

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
So waere es richtig (denke ich):

Code: Alles auswählen

sort -k1.3,1.6
Jo, so stimmts. Mit diesen Grenzen, durch Parameter ersetzt, hab ich die Sortierung auch benutzt.

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 18:54:37
... ich seh' schon wie ich heute mitten in der Nacht aufstehe, weil mich dieser Code nicht schlafen laesst, oder wie ich aus Alptraeumen von awk-Code, den ich nicht verstehe, aufschrecke ... und dann poste ich auch mal zu nachtschlafener Zeit. Waere dann gut, wenn noch jemand da waere, mit dem ich mir die Sache von der Seele reden koennte. :-D
Na, so schlimm ists hoffentlich auch nicht ;) (Ich hab zumindest nicht die Foren-Nachtschicht heute ;) ) Der Ablauf ist ähnlich wie bei den anderen Schnipseln (Sortieren, häufigste Mitte suchen, Wörter mit eben jener Mitte ausgeben). Nur minimal unnötig zusätzlich verschachtelt.

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Das kann ich jetzt wenigstens lesen. ;-) Toll finde ich, dass du so schoen kreative Ansaetze gewaehlt hast, waehrend wir anderen so straight-forward rangegangen sind.
Spannend wäre natürlich noch, das Ganze in einer Pipeline, ohne (Shell-)Variablen und mit einmal Einlesen des Wörterbuchs zu lösen – und (nur) die ausgewählten Wörter ausgegeben zu bekommen. Wenn ich das richtig mitverfolgt habe, sind wir da ja noch nicht angekommen (oder?!).


Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Dabei gibt es einen so eleganten Weg mit Traps, um das Temp-Dir automatisch aufraeumen zu lassen:
Da bin ich einmal faul … :oops: Ja, du hast natürlich Recht, dass das über trap die sicherste und sauberste Variante ist. Ich muss allerdings jedes Mal überlegen, welche Signale sinnvoll abzufangen sind. Das Pseudo EXIT verhält sich in z.B. dash und bash ja meine ich nicht gleich.

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
2) `sort -k1'. Soweit ich weiss ist `-k1' nicht anders als wenn man es ganz weglaesst.
Ich glaube, da vertust du dich. Die Manpage sagt:
man sort hat geschrieben: […] both are origin 1, and the stop position defaults to the line's end.
Also wäre das Standardverhalten eher, die ganze Zeile heranzuziehen. An der Stelle im Skript haben die Zeilen aber zwei Felder (Wortanzahl und Dateiname), nur das erste soll Schlüssel sein.
Manchmal bekannt als Just (another) Terminal Hacker.

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 20:15:39

JTH hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:02:54
Spannend wäre natürlich noch, das Ganze in einer Pipeline, ohne (Shell-)Variablen und mit einmal Einlesen des Wörterbuchs zu lösen – und (nur) die ausgewählten Wörter ausgegeben zu bekommen. Wenn ich das richtig mitverfolgt habe, sind wir da ja noch nicht angekommen (oder?!).
Dieser Vorschlag von eggy (halt noch bei sort wie eben besprochen korrigiert) kann das, AFAICS: viewtopic.php?f=34&t=182218&start=15#p1283933
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Dabei gibt es einen so eleganten Weg mit Traps, um das Temp-Dir automatisch aufraeumen zu lassen:
Da bin ich einmal faul … :oops: Ja, du hast natürlich Recht, dass das über trap die sicherste und sauberste Variante ist. Ich muss allerdings jedes Mal überlegen, welche Signale sinnvoll abzufangen sind.
Ich nehme immer: 0 1 2 15

(Edit: Das kann ich mir auch problemlos merken. Halt die ersten drei Zahlen am Stueck (EXIT, SIGHUB, SIGINT) und dann die 15 (SIGTERM). Signal 3 (SIGQUIT) ist das was ich nicht trappe, damit ich debuggen kann wenn ich das Temp-Dir anschauen will.)
Das Pseudo EXIT verhält sich in z.B. dash und bash ja meine ich nicht gleich.
Davon ist mir nichts bekannt, aber ich lerne gerne dazu.
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
2) `sort -k1'. Soweit ich weiss ist `-k1' nicht anders als wenn man es ganz weglaesst.
Ich glaube, da vertust du dich. Die Manpage sagt:
man sort hat geschrieben: […] both are origin 1, and the stop position defaults to the line's end.
Also wäre das Standardverhalten eher, die ganze Zeile heranzuziehen. An der Stelle im Skript haben die Zeilen aber zwei Felder (Wortanzahl und Dateiname), nur das erste soll Schlüssel sein.
Ja, eben, wenn *nur* nach dem ersten Feld sortiert werden soll, dann darf man *nicht* `-k1' verwenden, sondern muss `-k1,1' verwenden! Das ist unerwartet, aber nunmal so.

Allerdings macht es keinen Unterschied wenn man numerisch sortiert. Zeilen der Form ``Zahl Wort'' kann man ohne die Angabe eines Feldes numerisch sortieren.

Was ich aber eigentlich sagen wollte: `sort -k1' ist identisch zu nur `sort', weil beide von der ersten Spalte bis zum Ende der Zeile sortieren. Denn die erste Spalte ist der Beginn der Zeile.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 07.10.2021 22:08:49

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:15:39
JTH hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:02:54
Spannend wäre natürlich noch, das Ganze in einer Pipeline, ohne (Shell-)Variablen und mit einmal Einlesen des Wörterbuchs zu lösen – und (nur) die ausgewählten Wörter ausgegeben zu bekommen. Wenn ich das richtig mitverfolgt habe, sind wir da ja noch nicht angekommen (oder?!).
Dieser Vorschlag von eggy (halt noch bei sort wie eben besprochen korrigiert) kann das, AFAICS: viewtopic.php?f=34&t=182218&start=15#p1283933
Das war Quatsch, was ich da geschrieben habe.

Ich glaube, dass das gar nicht gehen kann. Denn wir muessen irgendwann man zaehlen, von welchem Mittelteil es am meisten Vorkommen gibt. Dazu muessen wir alle durchlesen. Dann sind wir aber schon am Ende. Bevor wir nicht am Ende sind, koennen wir nicht wissen, welcher Mittelteil der haeufigste ist. Da es jeder sein kann, muessten wir alle Woerter zwischenspeichern, was dann einem erneuten Durchlesen der Ausgangsdatei gleich kommt. Es wird also nicht ohne eines davon gegen: Zwischenspeichern oder nochmal Einlesen.
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von JTH » 07.10.2021 23:39:53

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:15:39
(Edit: Das kann ich mir auch problemlos merken. Halt die ersten drei Zahlen am Stueck (EXIT, SIGHUB, SIGINT) und dann die 15 (SIGTERM).
EXIT, INT und TERM nehme ich auch normalerweise. HUP wäre wohl sinnvoll, mir anzugewöhnen, wenns nicht gerade für andere Zwecke herhalten muss.

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:15:39
Das Pseudo EXIT verhält sich in z.B. dash und bash ja meine ich nicht gleich.
Davon ist mir nichts bekannt, aber ich lerne gerne dazu.
Nachdem ich wiedergefunden hab, was ich da im Hinterkopf hatte: (Zumindest) die beiden verhalten sich anscheinend unterschiedlich, wenn man nur EXIT trapt. dash ruft dann den Handler bei einem Signal nicht auf. Ein kleines, sich selbst killendes Skriptchen:

Code: Alles auswählen

for s in $1; do trap "echo '$s handler'" $s; done
sleep 1 &
${2:+kill $2 $$}
wait
Liefert folgendes:

Code: Alles auswählen

$ bash ./sh EXIT
EXIT handler
$ bash ./sh EXIT -sTERM
EXIT handler
Terminated
$ bash ./sh "EXIT TERM" -sTERM
TERM handler
EXIT handler
$ dash ./sh EXIT
EXIT handler
$ dash ./sh EXIT -sTERM
Terminated
$ dash ./sh "EXIT TERM" -sTERM
TERM handler
EXIT handler
Das Verhalten mag gewollt (stammts womöglich aus Posix?) sein, aber wenn man unbedacht nur EXIT trapt, könnte man drüber stolpern.


Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Ja, eben, wenn *nur* nach dem ersten Feld sortiert werden soll, dann darf man *nicht* `-k1' verwenden, sondern muss `-k1,1' verwenden! Das ist unerwartet, aber nunmal so.

[…]

Was ich aber eigentlich sagen wollte: `sort -k1' ist identisch zu nur `sort', weil beide von der ersten Spalte bis zum Ende der Zeile sortieren. Denn die erste Spalte ist der Beginn der Zeile.
Du hast natürlich völlig recht, das war Käse, was ich vorhin geschrieben habe (hätte mein eigenes Manpage-Zitat mal richtig lesen sollen :lol: ). Ist wohl etwas her, dass ich sort „exzessiv“ benutzt hab.

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 22:08:49
JTH hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 20:02:54
Spannend wäre natürlich noch, das Ganze in einer Pipeline, ohne (Shell-)Variablen und mit einmal Einlesen des Wörterbuchs zu lösen – und (nur) die ausgewählten Wörter ausgegeben zu bekommen.
[…]

Ich glaube, dass das gar nicht gehen kann. […]
Ja, ich denke auch, dass das nicht geht, ohne, dass man auf die ein oder andere Art zweimal über die Wortliste geht. Ich dachte mehr daran, das möglichst geschickt in der Pipeline zu verstecken, vielleicht die Zählung zwischendrin mit in die Wortzeilen zu hängen. Denn auch ein tac oder sort müssten ja alle Daten einmal be-/vorhalten, sonst würde das Umkehren oder Sortieren nicht funktionieren.
Manchmal bekannt als Just (another) Terminal Hacker.

tobo
Beiträge: 1996
Registriert: 10.12.2008 10:51:41

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von tobo » 08.10.2021 01:24:45

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
So waere es richtig (denke ich):

Code: Alles auswählen

sort -k1.3,1.6
Wobei es egal ist, ob wir den Rest hinten mitsortieren oder nicht.
Genau! Und gerade deswegen ist doch auch an eggys Sortierung nichts falsch.

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 08.10.2021 06:17:40

tobo hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 01:24:45
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
So waere es richtig (denke ich):

Code: Alles auswählen

sort -k1.3,1.6
Wobei es egal ist, ob wir den Rest hinten mitsortieren oder nicht.
Genau! Und gerade deswegen ist doch auch an eggys Sortierung nichts falsch.
:facepalm: Stimmt!

Das hier war ja echt ein idiotischer Post von mir: viewtopic.php?f=34&t=182218&start=15#p1283937 An dem ist inhaltlich einfach gar nichts richtig. :roll: ... es waere besser, ich wuerde etwas mehr nachdenken, bevor ich poste. :-D

Danke, dass du nicht locker gelassen hast, bis ich's auch blicke! :THX:
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 08.10.2021 08:31:12

Hier eine Loesung, die aus genau einer Pipeline besteht und alle Woerter mit dem haeufigsten Mittelteil ausgibt:

Code: Alles auswählen

#!/bin/sh

dict=/usr/share/dict/ngerman 

grep '^........$' "$dict" | sort -k1.3 | awk '
{
        m=substr($0,3,4)
        print (m==last)?++n:n=1, $0
        last=m
}
' | sort -nr | awk '
NR==1 {
        m=substr($2,3,4)
}
substr($2,3,4)==m {
        print $2
}
'
Funktionsweise:
- Sortiere nach den Mittelteilen
- Nummeriere wie oft der jeweilige Mittelteil schon hintereinander vorgekommen ist
- Sortiere numerisch, damit der haeufigste ganz oben ist
- Schaue dir den ersten an und gebe dann alle mit gleichem Mittelteil aus

Es wird nicht mehr als ein Mittelstueck und eine Zaehler gespeichert. (Plus dass beim Sortieren natuerlich zwangslaeufig der gesamte Inhalt zwischengespeichert werden muss.)

Nimmt bei mehreren gleich haeufig auftretenden Mittelteilen nur einen davon.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8818
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von Meillo » 08.10.2021 09:13:36

... bloss funktioniert mein sort irgendwie nicht richtig:

Code: Alles auswählen

: printf 'irgendwo\nangenehm\näugendes\n' | sort -k 1.3
irgendwo
angenehm
äugendes
``äugendes'' muesste vor ``angenehm'' kommen.

Sieht nach einer fehlenden Multibyte-Unterstuetzung aus. (Bei mir ist es ein GNU sort 8.13 ... vielleicht macht es ein neueres sort besser.)

Auf FreeBSD (sort 2.3-FreeBSD) tut es korrekt:

Code: Alles auswählen

$ printf 'irgendwo\nangenehm\näugendes\n' | sort -k 1.3
äugendes
irgendwo
angenehm
... dafuer kann dort der FreeBSD-awk kein UTF-8. :roll:

Ich habe schon alles mit den Locales ausprobiert.

Ach! Das naechste Mal schreibe ich rein, dass nur US-ASCII verarbeitet werden soll ... 8O


Edit:
Hier mein Script (das zumindest mit englischen Wortlisten funktioniert) nochmal ein bisschen kuerzer:

Code: Alles auswählen

#!/bin/sh

dict=/usr/share/dict/words 

grep '^........$' "$dict" | sort -k1.3 | awk '
{
        m=substr($0,3,4)
        print (m==last)?++n:n=1, m, $0
        last=m
}
' | sort -nr | awk '
NR==1 { m=$2 }
$2==m { print $3 }
'
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von JTH » 08.10.2021 11:18:54

Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Wobei es egal ist, ob wir den Rest hinten mitsortieren oder nicht.
tobo hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 01:24:45
Genau! Und gerade deswegen ist doch auch an eggys Sortierung nichts falsch.
Ich glaube, das ist es tatsächlich nicht (je nach Zielsetzung natürlich). Vielleicht ist uns das hier in mehreren Beiträgen schon auf die Füße gefallen. Wenn man mal voraussetzt, dass die Wörterbuchdateien für die Sprache sinnvoll vorsortiert sind und man als Ausgabe auf die gleiche Weise sortierte Wörter haben möchte, macht es nen Unterschied, ob man wirklich nur den Mittelteil sortiert oder den ganzen hinteren Substring: Das erste Sortierergebnis ist eher unerwartet:

Code: Alles auswählen

$ printf "aab\nabb\nbaa\nbba\n" | sort -k1.2
baa
aab
bba
abb
$ printf "aab\nabb\nbaa\nbba\n" | sort -k1.2,1.2
aab
baa
abb
bba
(Oder denk ich da womöglich um zu viele Ecken?)


Meillo hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 08:31:12
Hier eine Loesung, die aus genau einer Pipeline besteht und alle Woerter mit dem haeufigsten Mittelteil ausgibt:
Ja genau, an so einer Variante war ich gestern am Grübeln und Basteln :THX:

Meillo hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 09:13:36
Sieht nach einer fehlenden Multibyte-Unterstuetzung aus. (Bei mir ist es ein GNU sort 8.13 ... vielleicht macht es ein neueres sort besser.)
Kann ich mit 8.32 nachvollziehen. Wahrscheinlich wird tatsächlich byteweise nach irgendwo, angenehm, äugendes sortiert.

Man könnte das Problem umgehen, indem man mit (dem anscheinend mutlibyte fähigen) (g)awk die Mittelteile raussucht, dann direkt nach der neuen Mittelteil-Spalte sortiert (die naive, byteweise Interpretation durch sort ist dann egal) und auch stabil sortiert, um die Reihenfolge aus dem Dictionary zu behalten:

Code: Alles auswählen

awk 'length == 8 { print(substr($0, 3, 4), $0) }' "$1" |
sort -s -k1,1 -k2,2r |
awk '
{
        print ($1==last)?++n:n=1, $0
        last=$1
}
' | sort -nrs | awk '
NR==1 { m=$2 }
$2==m { print $3 }
'
Mag sein, dass man nicht an beiden Stellen stabil sortieren müsste. Aber das scheint so auch mit dem deutschen Wörterbuch zu funktionieren.
Manchmal bekannt als Just (another) Terminal Hacker.

tobo
Beiträge: 1996
Registriert: 10.12.2008 10:51:41

Re: Programmieraufgabe von Knuth: Woerter mit den gleichen 4 Buchstaben in der Mitte

Beitrag von tobo » 08.10.2021 11:57:23

JTH hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 11:18:54
Meillo hat geschrieben: ↑ zum Beitrag ↑
07.10.2021 19:24:19
Wobei es egal ist, ob wir den Rest hinten mitsortieren oder nicht.
tobo hat geschrieben: ↑ zum Beitrag ↑
08.10.2021 01:24:45
Genau! Und gerade deswegen ist doch auch an eggys Sortierung nichts falsch.
Ich glaube, das ist es tatsächlich nicht (je nach Zielsetzung natürlich).
Für die gestellte Aufgabe ist es egal. Es ist ja nur relevant, dass die Wörter mit den 4 gleichen mittleren Buchstaben untereinander stehen. Diese Wörter könnte man danach auch gerne noch in ihrer Reihenfolge randomisieren.
Das erste Sortierergebnis ist eher unerwartet:

Code: Alles auswählen

$ printf "aab\nabb\nbaa\nbba\n" | sort -k1.2
baa
aab
bba
abb
$ printf "aab\nabb\nbaa\nbba\n" | sort -k1.2,1.2
aab
baa
abb
bba
Wieso ist das unerwartet - bei gleichem 2. Buchstaben folgt im 3. Buchstaben a vor b. Wäre das die Aufgabenstellung gewesen (gleicher 2. Buchstabe von 3), dann wären die beiden Wortlisten gleichwertig. Da beide Sortierungen nicht stabil sind, wären hier auch noch andere Reihenfolgen denkbar und richtig (2. Sortierung bzw. bei größerer Eingabe auch 1.).

PS: sort 8.30 liefert auch das falsche Ergebnis.

Antworten