Closed pigreco closed 1 year ago
Caro totò, con Miller 5 (dovresti avere questo), un modo non elegante è questo:
mlr --csv nest --explode --values --across-records -f scritta --nested-fs "-" then \
put -S '$toto=regextract($scritta,"[0-9]+")' then \
sort -f den_estesa -n toto then \
cut -x -f toto then \
nest --implode --values --across-records --nested-fs "-" -f scritta ordinare_scritta.csv
Di base mette tutto in colonna splittando per -
, poi crea una colonna con i soli numeri, ordina per questa e poi rimetta tutto insieme
Una versione, che ordina anche 12B, 12, 12A, per lo stesso record
mlr --csv nest --explode --values --across-records -f scritta --nested-fs "-" then \
put -S '$totoN=regextract($scritta,"[0-9]+");$totoT=regextract($scritta,"[a-zA-Z]+")' then unsparsify then sort -f den_estesa -n totoN -f totoT then cut -r -x -f "toto+" then nest --implode --values --across-records --nested-fs "-" -f scritta ordinare_scritta.csv
Una versione, che ordina anche 12B, 12, 12A, per lo stesso record
funziona perfettamente, grazie:
ricetta fatta e pubblicata,
grazie
https://tansignari.opendatasicilia.it/ricette/script/ordinare_elementi_array/
Ciao Totò, anche se Andrea ti ha già risposto inserisco qui sotto due versioni della stessa ricetta in python:
La prima più pythonica...
import pandas as pd
df = pd.read_csv('ordinare_scritta.csv')
df['scritta']=df.scritta.map(lambda x:
"-".join([item.replace('/0','')
for item in [item[1:] if item[0]=='0' else item
for item in sorted([t.zfill(2)+"/0" if t.isdigit() else t
for t in [f'0{t}' if t.find('/')==1 else t
for t in x.split('-')]], key=str)]]))
df.to_csv('ordina_scritta_ok.csv',index=False)
...la stessa di prima, più leggibile però:
import pandas as pd
df = pd.read_csv('ordinare_scritta.csv')
def ordina(x):
tmp = x.split('-')
a = [f"0{t}" if t.find('/')==1 else t for t in tmp]
b = [t.zfill(2)+"/0" if t.isdigit() else t for t in a]
tmp2=sorted(b, key=str)
first_ord = [item[1:] if item[0]=='0' else item for item in tmp2]
second_ord = [item.replace('/0','') for item in first_ord]
return "-".join(second_ord)
df['scritta']=df.scritta.map(ordina)
df.to_csv('ordina_scritta_ok.csv',index=False)
Ciao
Quanto voglio bene a @gpirrotta ?💜
grazie mille @gpirrotta, sono belle soluzioni, prima o poi inizierò a studiare Python sul serio.
aggiungerò le soluzioni alla ricetta ;-)
aggiungo anche l'ultima arrivata, soluzione usando le espressioni di QGIS
array_to_string(
array_foreach(
array_sort(
with_variable('lista',
string_to_array('5/A-5-4-8-3-14-6-9-7-1-10-7/B-2-7/A' ,'-'),
array_foreach(generate_series(0, array_length(@lista)-1),
lpad(regexp_substr( (@lista[@element]),'(\\d+)'),3,'0')
||'|'||
if(regexp_substr((@lista[@element]),'([a-zA-Z/]+)') !='',
regexp_substr((@lista[@element]),'([a-zA-Z/]+)'),
' ') -- uno spazio
||'|'||
@lista[@element]))),
regexp_replace( @element,'^.+\\|(.+)$','\\1'))
)
Suggerirei questa forma per una funzione personalizzata che restituisca un array:
commentando l'ultima riga e decommentando la penultima restituisce una stringa
from qgis.core import *
from qgis.gui import *
@qgsfunction(args='auto', group='Custom', referenced_columns=[])
def array_sort_special(value1, feature, parent):
"""
Ordina un array alfanumerico numericamente
<h2>Example usage:</h2>
<ul>
<li>array_sort_special('5/A-5-4-8-3-6-9-7-1-10-7/B-2-7/A') -> ['1','2','3','4','5','5/A','6','7','7/A','7/B','8','9','10']</li>
</ul>
"""
data = value1.split('-')
r = sorted(data, key=lambda item: (int(item.partition('/')[0])
if item[0].isdigit() else float('inf'), item))
#return (','.join(r))
return r
Suggerirei questa forma per una funzione personalizzata che restituisca un array:
grazie @Korto19 , anche questa soluzione andrà nella ricetta :-)
Ecco una soluzione ancora più light, che sfrutta il natural sorting e le utility di sistema.
Nella shell infatti basta usare
echo "15,1,2/AX,22,1/C,1/A,1/BA,2,3" | tr , "\n" | sort -V | paste -sd, -
per avere
1,1/A,1/BA,1/C,2,2/AX,3,15,22
E questo è portabile penso in tutti gli ambienti. In Miller c'è la funzione system
. Ad esempio a partire da
a,b
1,"15,1,2/AX,22,1/C,1/A,1/BA,2,3"
si lancia
<input.txt mlr --c2p --barred cat then put -S '$toto=system("echo ".$b." | tr , \"\n\" | sort -V | paste -sd, -")'
e si ottiene
+---+-------------------------------+-------------------------------+
| a | b | toto |
+---+-------------------------------+-------------------------------+
| 1 | 15,1,2/AX,22,1/C,1/A,1/BA,2,3 | 1,1/A,1/BA,1/C,2,2/AX,3,15,22 |
+---+-------------------------------+-------------------------------+
La ricetta è stata fatta, chiudo
https://tansignari.opendatasicilia.it/ricette/script/ordinare_elementi_array/
Ho una colonna di un CSV caratterizzata da una serie di numeri separati da
-
come in figura:come ordinare numericamente (Natural Sorting) i valori all'interno delle celle nella colonna
scritta
?esempio:
da:
5/A-5-16/B-4-18-8-15-22-3-14-12-6-16/A-9-11-13-7-21-1-19-10-7/A-17-20-2
a:
1-2-3-4-5-5/A-6-7-7/A-8-9-10-11-12-13-14-15-16/A-16/B-17-18-19-20-21-21
usare la funzione
array_sort
ordinerebbe alfabeticamente e non va.allego un csv di prova ordinare_scritta.csv