perl -F, -lane '
exists $h{$F[0]} or $h[$h{$F[0]}=@h]=$_;
$h=$_; /,false$/ or $_=$h for $h[$h{$F[0]}];
END{ print for @h; }
' duplicates.file
Struktury danych:
- Hash,
%h
którego klucze są pierwszymi polami (AAA, BBB, CCC itp.), A odpowiadającymi im wartościami są liczby określające kolejność napotkania kluczy. Zatem np. Klucz AAA => 0, klucz BBB => 1, klucz CCC => 2.
- Tablica,
@h
której elementami są linie zawarte w kolejności drukowania. Więc jeśli zarówno prawda, jak i fałsz zostaną znalezione w danych, wówczas wartość fałszu przejdzie do tablicy. OTW, jeśli istnieje jeden typ danych, to byłby obecny.
Innym sposobem jest użycie GNU sed:
sed -Ee '
G
/^([^,]*),(false|true)\n(.*\n)?\1,\2(\n|$)/ba
/^([^,]*)(,true)\n(.*\n)?\1,false(\n|$)/ba
/^([^,]*)(,false)\n((.*\n)?)\1,true(\n|$)/{
s//\3\1\2\5/;h;ba
}
s/([^\n]*)\n(.*)$/\2\n\1/;s/^\n*//
h;:a;$!d;g
' duplicates.file
FWIW, kod równoważny POSIX dla powyższego kodu GNU-sed jest wymieniony poniżej:
sed -e '
G
/^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2$/ba
/^\([^,]*\),\(false\)\n\(.*\n\)\{0,1\}\1,\2\n/ba
/^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2$/ba
/^\([^,]*\),\(true\)\n\(.*\n\)\{0,1\}\1,\2\n/ba
/^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false$/ba
/^\([^,]*\),true\n\(.*\n\)\{0,1\}\1,false\n/ba
/^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true$/{
s//\3\1\2/
h
ba
}
/^\([^,]*\)\(,false\)\n\(\(.*\n\)\{0,1\}\)\1,true\n/{
s//\3\1\2\n/
h
ba
}
y/\n_/_\n/
s/\([^_]*\)_\(.*\)$/\2_\1/;s/^_*//
y/\n_/_\n/
h;:a;$!d;g
' duplicates.file
Wyjaśnienie
- W tej metodzie przechowujemy wynik do ostatecznego wydrukowania w przestrzeni wstrzymania.
- Do każdego odczytanego wiersza dołączamy przestrzeń wstrzymania do obszaru wzoru w celu zbadania bieżącej linii względem istniejącego stanu przestrzeni wstrzymania.
- Teraz podczas tego porównania może się zdarzyć 5 rzeczy:
- a) Bieżąca linia pasuje gdzieś w linii wstrzymania i false: false.
- [AKCJA] Ponieważ znaleziono ten sam stan fałszywy, nic nie rób.
- b) Bieżąca linia odpowiada gdzieś w linii wstrzymania i true: true.
- [AKCJA] Ponieważ znaleziono ten sam stan prawdziwy, nic nie rób.
- c) Bieżąca linia odpowiada gdzieś w linii wstrzymania i true: false.
- [AKCJA] Ponieważ stan fałszywy już istnieje, nie rób nic.
- d) Bieżąca linia odpowiada gdzieś w linii wstrzymania i false: true.
- [DZIAŁANIE] Wymaga to pewnej pracy, ponieważ musimy zastąpić fałszywą linię dokładnie w tej samej pozycji, w której znajduje się prawda.
- e) Bieżąca linia NIE pasuje nigdzie w linii wstrzymania.
- [AKCJA] Przenieś obecną linię na koniec.
Wyniki
AA,false
BB,false
CC,false
DD,true
true
jeśli jest to pierwsza instancja pierwszej kolumny?