J'ai un fichier csv avec un contenu comme ci-dessous

source,address,table,tableName,sym,symSet
source_one,addr1:port1:id1:pass1,table_one,tableName1,syms_one,SYM1 SYM2 SYM3
source_two,addr2:port2:id2:pass2,table_two,tableName2,syms_two,SYM21 SYM22 SYM23

Mon code pour charger un csv dans une table est comme ci-dessous

table:("******";enlist ",") 0: `sourceFileName.csv

Je souhaite créer un dictionnaire à partir du contenu de 'table' dans le format ci-dessous

source_one|addr1:port1:id1:pass1
table_one|tableName1
syms_one|SYM1 SYM2 SYM3
source_two|addr2:port2:id2:pass2
table_two|tableName2
syms_two|SYM21 SYM22 SYM23

Comment puis-je y parvenir?

Merci!

3
CleanSock 22 nov. 2017 à 18:28

4 réponses

Meilleure réponse

Compte tenu du tableau défini ci-dessus, vous pouvez utiliser value pour extraire les données du tableau sans en-têtes de colonne:

q)value each table
"source_one" "addr1:port1:id1:pass1" "table_one" "tableName1" "syms_one" "SYM1 SYM2 SYM3"
"source_two" "addr2:port2:id2:pass2" "table_two" "tableName2" "syms_two" "SYM21 SYM22 SYM23"

De là, vous pouvez {{X 0}} la sortie pour donner une seule liste qui peut ensuite être cut en paires (2):

q)2 cut raze value each table
"source_one" "addr1:port1:id1:pass1"
"table_one"  "tableName1"
"syms_one"   "SYM1 SYM2 SYM3"
...

Enfin, utiliser flip le met dans un format qui peut être utilisé pour créer un dictionnaire en utilisant !:

(!). flip 2 cut raze value each table
"source_one"| "addr1:port1:id1:pass1"
"table_one" | "tableName1"
"syms_one"  | "SYM1 SYM2 SYM3"
"source_two"| "addr2:port2:id2:pass2"
"table_two" | "tableName2"
"syms_two"  | "SYM21 SYM22 SYM23"

Si les clés doivent être des symboles, vous pouvez utiliser @ apply pour les convertir avant de créer le dictionnaire:

(!). @[;0;`$]flip 2 cut raze value each table

Une meilleure approche peut être de créer la table sans utiliser enlist et de supprimer les en-têtes de colonne avec 1_, avant d'utiliser la même méthode pour créer le dictionnaire:

(!). flip raze cut[2]each 1_flip("******";",") 0: `:source.csv
1
Thomas Smyth 22 nov. 2017 à 17:49

Je renoncerais à la création de table et ferais quelque chose comme ceci:

q)(!). flip 2 cut raze ","vs/:1_read0`source.csv
"source_one"| "addr1:port1:id1:pass1"
"table_one" | "tableName1"
"syms_one"  | "SYM1 SYM2 SYM3"
"source_two"| "addr2:port2:id2:pass2"
"table_two" | "tableName2"
"syms_two"  | "SYM21 SYM22 SYM23"

Explication. De droite à gauche, d'abord, 1_read0 lit le fichier source comme une liste de lignes et supprime la première ligne. Deuxièmement, ","vs/: coupe chaque ligne sur "," séparateurs. Troisièmement, 2 cut raze aplatit la liste des listes et la coupe par paires. Quatrièmement, flip transpose la liste de paires en la transformant en une paire de listes. Enfin, (!). construit un dictionnaire à partir d'une paire de listes contenant des clés et des valeurs. Notez que (!).(x;y) se traduit par x!y.

1
Alexander Belopolsky 22 nov. 2017 à 18:09

Une façon serait quelque chose comme ceci:

q)(!) . flip raze 2 cut'1_flip("******";",")0:`:test.csv
"source_one"| "addr1:port1:id1:pass1"
"table_one" | "tableName1"
"syms_one"  | "SYM1 SYM2 SYM3"
"source_two"| "addr2:port2:id2:pass2"
"table_two" | "tableName2"
"syms_two"  | "SYM21 SYM22 SYM23"

(Si vous voulez que les clés et valeurs soient des symboles, remplacez les * dans les paramètres 0: par S)

Cela fonctionne en lisant le fichier sous forme de listes de chaînes, en retournant dans les lignes d'origine, en supprimant la première (c'est-à-dire les en-têtes), en exécutant 2 cut sur chaque ligne pour la scinder en paires, en utilisant raze pour supprimer un niveau d'imbrication et utilise enfin dot apply pour appliquer le {{X2 }} (c'est-à-dire créer un dictionnaire) à ce retourné, de sorte que l'argument gauche de ! soit les clés et l'argument droit les valeurs.

2
Jonathon McMurray 22 nov. 2017 à 16:00

Vous pouvez également utiliser 0: pour analyser directement les paires clé-valeur, mais cela nécessiterait une modification de la façon dont votre fichier texte est stocké.

Besoin de supprimer la première ligne et d'ajouter une virgule à la fin de chaque ligne:

$ cat test.txt
source_one=addr1:port1:id1:pass1,table_one=tableName1,syms_one=SYM1 SYM2 SYM3,
source_two=addr2:port2:id2:pass2,table_two=tableName2,syms_two=SYM21 SYM22 SYM23,

S'il est facile de changer la charge devient alors une ligne:

q)(!). "S=,"0: raze  read0 `:test.txt
source_one| "addr1:port1:id1:pass1"
table_one | "tableName1"
syms_one  | "SYM1 SYM2 SYM3"
source_two| "addr2:port2:id2:pass2"
table_two | "tableName2"
syms_two  | "SYM21 SYM22 SYM23"

Cela a l'avantage sur le chargement dans une table si les données sont irrégulières, par exemple, aucune ligne n'a jamais de source, de table et de sym. S'ils l'ont fait, pourquoi ne pas les avoir simplement comme noms de colonnes dans une table?

3
emc211 22 nov. 2017 à 16:26
47438407