Merci beaucoup @ Sve@r
Mais il faut vraiment que je me mette à ce langage.
Un conseil a donner pour un débutant?
Merci beaucoup @ Sve@r
Mais il faut vraiment que je me mette à ce langage.
Un conseil a donner pour un débutant?
Oui: RTFM (read the fucking manual) Lis la putain de documentation
Comme il n'a jamais donné le fichier d'entrée, utilisant toujours des exemples de test pour ses algo, j'ai alors essayé de faire un script souple permettant de traiter ensuite n'importe quel format d'entrée. Ainsi si le format d'entrée change (que le séparateur n'est pas une tabulation mais un point-virgule par exemple), je garantis quand-même mon format de sortie...
Oui un fichier peut n'avoir qu'un ou deux cartons parce que le groupe suivant est au nombre de 4 ce qui ferait alors dépasser. Regarde son tout premier exemple...
Le fichier n° 1 ne contient que 2 articles parce qu'il y a 3 cartons "454" et qu'on ne peut pas mettre en plus ces 3 dans le fichier n° 1. Toutefois le carton n° 65 qui est unique peut quand-même rentrer dans le fichier n° 2...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 ZZZ 88 1 CCDE 88 1 AZDSDS 454 2 SDSEE 454 2 AAZE 454 2 TTGYH 65 2
Prendre un tuto et le lire puis se mettre à résoudre ses problèmes. Tu en as un justement sur le site developpez.net...
On le dit plutôt pour quelqu'un qui pose des questions bateau, comme par exemple comment fonctionne cut ou ls, pas pour un débutant qui demande comment apprendre le langage...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
@ Sve@r: Tu te compliques la vie: il ne cherche pas d'optimisation.
S'il en cherchait une, je ferais la liste des numCarton à 1, 2, 3 et 4 éléments et les arrangements optimaux seraient:
4
3 1
2 2
2 1 1
1 1 1 1
Le résidu imparfait serait:
3
2 1
2
1 1
1
Tout ça avec awk bien sur (toujours a[$2]++ et for (i in a) )
Reste à déterminer dans chaque cas le facteur limitant.
J'avais commencé à travailler de mon côté.
J'ai un resultat dans mon tableau res qui devrait être de 2 3 1 2 2
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 declare -a NumCarton NumCarton=(88 88 454 454 454 65 874 874 21 21) declare -A res for carton in "${NumCarton[@]}" do echo "carton: $carton" res[$carton]=$((${res[$carton]}+1)) done echo ${res[@]}
Au lieu de cela j'ai l'impression que le mon tableau res est trié en quelque sorte.
Ai-je fais une erreur je n'en vois pas .
J'ai pas dit qu'il en cherchait, j'ai juste dit que mon code reproduisait les résultats montrés dans son exemple (et, sous-entendu, en espérant que les données restent toujours triées par n° de carton). D'ailleurs moi non plus je n'optimise pas, je me contente juste de remplir les fichiers tant que ça rentre. Prends par exemple le cas suivant:
Mon algo placera le carton 65 dans le fichier n° 3 alors qu'un algo optimisé le placerait dans le n° 1...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 ZZZ 88 CCDE 88 AZDSDS 454 SDSEE 454 AAZE 454 PAPA 454 TTGYH 65
Perso je prendrais plutôt Python mais bon, chacun sa façon de se compliquer la vie...
Ben oui. Tu incrémentes res[carton]. Donc au premier carton (88) t'as res[88] qui est créé. Quand tu en es au carton 21, t'as res[21] qui est alors créé. Et au final, quand tu affiches la totalité du tableau res, ça affiche alors res[21] avant res[88]...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Mais comment alors faire pour afficher exactement ce que je veux c'est-à-dire: 2 3 1 2 2
Ben faut que tu te débrouilles pour faire une association 88=0; 454=1; 65=2 etc. pour pouvoir stocker "2" (représentant le nb de colis n° 88) dans l'élément [0]; "3" (représentant le nb de colis n° 454) dans l'élément 1 etc.
Accessoirement ce genre de mécanisme est possible en shell mais au prix de grandes manipulations car il n'est absolument pas fait pour ça. T'as en effet dans Unix/Linux d'autres outils de programmation bien plus adaptés à ce genre de problème.
Exemple en Python
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 #!/usr/bin/env python # -*- coding: utf-8 -*- NumCarton=(88, 88, 454, 454, 454, 65, 874, 874, 21, 21) res={} for carton in NumCarton: res[carton]=(res[carton] + 1) if carton in res.iterkeys() else 1 print "; ".join("carton %d: %d" % (k, v) for (k, v) in res.iteritems())
Et le résultat
Et si tu veux le résultat dans l'ordre d'arrivée des cartons, l'association dont je parle n'est alors pas très compliquée à faire...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 $ python essai.py carton 88: 2; carton 65: 1; carton 874: 2; carton 21: 2; carton 454: 3
Code python : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #!/usr/bin/env python # -*- coding: utf-8 -*- # Retourne l'index correspondant à un n° de carton def index(tab, carton): try: return [x[0] for x in tab].index(carton) except (IndexError, ValueError): return None # try # index() NumCarton=(88, 88, 454, 454, 454, 65, 874, 874, 21, 21) res=[] for carton in NumCarton: idx=index(res, carton) if idx is None: res.append([carton, 1]) # Ici je fais l'association => j'ajoute le dernier carton arrivé dans mon tableau qui restera alors dans ce même ordre else: res[idx][1]+=1 # if # for print "; ".join("carton %d: %d" % (x[0], x[1]) for x in res)
Et le résultat
Maintenant si tu veux quand-même le faire en shell, c'est possible. Tu peux par exemple stocker dans ton tableau non pas 2 3 en positions [88] et [454] mais "88;2" "454;3" en positions [0] et [1]. Puis dès que t'as un carton 454, tu cherches dans le tableau sa position [1], tu incrémentes sa quantité et tu le restockes (ce que j'ai fait dans mon second exemple Python en fait). Pas facile mais ce sera un bel exercice de style.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 $ python essai2.py carton 88: 2; carton 454: 3; carton 65: 1; carton 874: 2; carton 21: 2
[edit]Bon ben je l'ai fait aussi en shell
Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #!/bin/bash index() { ( carton=$1; shift i=0 for x in $* do test "$(echo "$x" |cut -f1 -d:)" = "$carton" && echo $i i=$(($i+1)) done ) } NumCarton=(88 88 454 454 454 65 874 874 21 21) declare -a res for carton in "${NumCarton[@]}" do idx=$(index $carton "${res[@]}") test -n "$idx"\ && res[$idx]="$carton:$(($(echo ${res[$idx]} |cut -f2 -d:)+1))"\ || res[${#res[*]}]="$carton:1" done echo "${res[@]}"
Et le résultat
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 $ ./essai2.sh 88:2 454:3 65:1 874:2 21:2
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
[mode_Teigneux]
Malgré le pouce baissé du message #17, j'en remets une couche, toujours en une ligne:
[/mode_Teigneux]
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 $ awk '(NR>1){a[$2]++;} END{for (i in a) printf i":"a[i]" ";print "";}' cartons.txt 874:2 21:2 65:1 454:3 88:2 $
Le résultat (qui n'est d'ailleurs pas le même que le tien ce qui est étonnant sauf si t'as changé ton jeu d'essais sans nous le dire) n'est pas dans l'ordre des cartons du fichier d'origine. T'as pas vu que c'est ce qu'il demande depuis le message #26 ???
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 $ cat cartons.txt NumArt NumCarton ZZZ 88 CCDE 88 AZDSDS 454 SDSEE 454 AAZE 454 TTGYH 65 DFDF 874 ARFFF 874 TRUCC 21 TOUCK 21 $ awk '(NR>1){a[$2]++;} END{for (i in a) printf i":"a[i]" ";print "";}' cartons.txt 454:3 65:1 21:2 88:2 874:2 $
Ben entre un programme en une ligne qui ne répond pas à la demande, et un programme en 500 qui y répond, moi je fais mon choix et ce n'est certainement pas le code en une ligne.![]()
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Envoyé par bricko
Code BASH : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 $ declare -ai nbArt $ $ while read -r item carton > do > ((${#Cartons[$carton]})) && Cartons[$carton]+="|$item" || Cartons[$carton]="$item" > nbArt[$carton]+=1 > done < $fichier $les tableaux indexés n'ont pas besoin d'être déclarés explicitement.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 $ for i in ${!Cartons[@]} > do > echo "le carton n° $i contient ${nbArt[$i]} articles : ( ${Cartons[i]//|/ } )" > done le carton n° 21 contient 2 articles : ( TRUCC TOUCK ) le carton n° 65 contient 1 articles : ( TTGYH ) le carton n° 88 contient 2 articles : ( CCDE ZZ ) le carton n° 454 contient 3 articles : ( AZDSDS SDSEE AAZE ) le carton n° 874 contient 2 articles : ( DFDF ARFFF )
nbArt est déclaré explicitement pour lui attribuer le type numérique.
Merci beaucoup pour votre aide.
Mais j'aurais encore besoin de vous.
J'ai pas très bien compris la fonction de @Sve@r
La fonction split() que fait-elle exactement?
Dans mon premier code, j'ai regroupé dans le tableau d'entrée l'article et le carton en les séparant par une tabulation, comme cela: data=("ZZZ 88" "CCDE 88" "AZDSDS 454" "SDSEE 454" "AAZE 454" "TTGYH 65" "DFDF 874" "ARFFF 874" "TRUCC 21" "TOUCK 21" "_EOF_ _EOF_"). En effet, en programmation structurée on aime bien regrouper ensemble les données qui vont ensembles. Ca aide à la lecture et à la maintenance. Par exemple si je dois rajouter ou enlever un article et un carton, je n'ai qu'une modif à faire.
Toutefois, à certains moments du code, j'ai besoin de récupérer le n° d'article ou bien le n° de carton. Ben c'est ce que fait la fonction split(). Je lui passe une information groupée (exemple "ZZZ 88" et la position de l'élément que je veux récupérer (1 pour l'article ou 2 pour le carton) et elle, elle coupe l'information pour extraire ce que je veux (ZZZ ou 88).
Ensuite, pour renvoyer la valeur récupérée, je me contente de l'afficher. En effet, en shell, le return dans une fonction n'a pas le même sens que dans les autres langages dans la mesure où la valeur retournée (qui soit être impérativement un nombre entre 0 et 255) n'est là que pour indiquer un état ok/pas ok (0=ok, autre chose=pas ok).
Donc si je veux écrire une fonction qui renvoie une valeur ("renvoie" dans le sens qu'on utilise habituellement dans les autres langages c'est à dire une chaine, un calcul mathématique, etc), je dois lui faire faire un affichage de l'élément que je veux renvoyer. Et l'appelant, lui, pour récupérer l'élément renvoyé par la fonction, doit utiliser le mécanisme de récupération d'éléments externes, c'est à dire les backquottes ou le $(...).
Exemple
Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 #!/bin/bash # Fonction qui concatène deux chaines fct() { echo "$1$2" } chaine=$(fct "Hello" "World") echo "chaine=[$chaine] chaine=`fct "World" "Hello"` echo "chaine=[$chaine]
J'aurais pu très bien ne pas mettre de fonction et couper l'info à chaque fois que j'en avais besoin. Suffisait de reprendre le echo |cut... à chaque fois que j'appelais split.
Toutefois j'ai aussi envisagé que le format d'entrée puisse changer (tu ne nous l'as jamais donné). Et que par exemple le séparateur article/carton ne soit plus la tabulation mais par exemple un espace, ou bien les deux-points("ZZZ:88"). Dans ce cas, il aurait fallu modifier tous les endroits où je découpais l'information.
Pour éviter ce soucis, j'ai préféré passer par une fonction dédiée. Comme ça, si le séparateur change, il suffit alors de modifier la fonction et ça suffit (factorisation de code).
Exemple avec le séparateur ":"
Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 #!/bin/bash # fonction qui extrait une partie de l'info split() { echo "$1" |cut -f$2 -d: } # Jeu de test data=("ZZZ:88" "CCDE:88" "AZDSDS:454" "SDSEE:454" "AAZE:454" "TTGYH:65" "DFDF:874" "ARFFF:874" "TRUCC:21" "TOUCK:21" "_EOF_:_EOF_") ... (reste du code sans changement)...
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Bonjour,
Merci pour toutes ces explications.
Le format d'entrée de mon input est un fichier. j'avais commencé avec des tableaux vu que je ne savais comment manipuler les fichiers.
Reste à voir comment je vais transformer mon fichier d'entrée en tableau.
Bonjour,
le script fait appelle à une fonction.
Code : Sélectionner tout - Visualiser dans une fenêtre à part buffer
Je ne suis pas sur de bien comprendre.
Est-ce une fonction ou un tableau.
Aussi dans le code je vois une variablequi est évoquée alors qu'elle n'est pas déclarée avant.
Code : Sélectionner tout - Visualiser dans une fenêtre à part mem_carton
Quelle étrange langage qu'est shell
Pouvez-vous m'éclairer ma lanterne
Oui ça on l'avait compris. C'est la façon dont il est écrit qui nous intéresse (comment sont séparés les infos, est-ce une info par ligne (n° d'article puis n° de carton) ou bien (un peu plus conforme) les deux ensembles sur une ligne. Et si c'est le cas, comment sépares-tu le n° d'article du carton (un espace, une tabulation, un point-virgule, ...)
C'est expliqué dnas les tutos. Faudrait quand-même commencer à les lire un peu...
T'es pas obligé. Si le format du flux entrant est le même que le tableau (<article><tabulation><carton>), on peut adapter très facilement le script au fichier. Suffit de changer le premier for...
Si c'était une fonction, alors son appel serait en début de ligne (ou en début de parenthèses dans le cas de var=$(...)). Tu vois bien que son identificateur commence par un "$" (if test "${#buffer[*]}" -gt 0) donc c'est une variable. Et comme il y a des crochets, c'est un tableau.
Ce n'est pas obligé en shell. T'as qu'à essayer dans ta fenêtre terminal de taper echo :$toto: et bien que la variable $toto n'existe pas, tu auras à l'écran :: sans problème ni message d'erreur.
Toutefois dans mon test, je suis obligé de l'encadrer de guillemets doubles. Parce que si j'écrivais if test $carton != $mem_carton et que la variable n'existe pas, au premier appel le shell verrait if test 88 != ce qui lui semblerait incompréhensible (une inégalité implique obligatoirement deux opérandes).
Ainsi avec les guillemets, au premier carton le shell voit if test "88" != "" et non seulement l'instruction ne pose pas de soucis mais en plus l'inégalité étant vérifiée, le premier carton trouvé le fait entrer dans le bloc "nouveau carton" ce qui est parfait.
Mon Tutoriel sur la programmation «Python»
Mon Tutoriel sur la programmation «Shell»
Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
Et on poste ses codes entre balises [code] et [/code]
Mon fichier d'entrée est plutôt.
Code : Sélectionner tout - Visualiser dans une fenêtre à part <article> <carton>
La séparation est faite par une tabulation.
Dans ce cas comment opérer les changements dans ma boucle.
Code : Sélectionner tout - Visualiser dans une fenêtre à part for
Je ne suis pas très fier de cette solution, mais ça fait le job:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 $ cat cartons.txt NumArt NumCarton ZZZ 88 CCDE 88 AZDSDS 454 SDSEE 454 AAZE 454 TTGYH 65 DFDF 874 ARFFF 874 TRUCC 21 TOUCK 21
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 $ rm -f file_cartons*.txt;awk '(NR==1){next;} (a[$2]==0){printf "\n"} {a[$2]++; printf " "$0;}' cartons.txt|awk 'NR==1{next;} {if (e+NF<9) {e=e+NF;carton=carton$0;} else {num++;print carton>"file_cartons"num".txt";carton=$0;e=NF} } END{num++;print carton>"file_cartons"num".txt";}';grep [A-Z] file_cartons* file_cartons1.txt: ZZZ 88 CCDE 88 file_cartons2.txt: AZDSDS 454 SDSEE 454 AAZE 454 TTGYH 65 file_cartons3.txt: DFDF 874 ARFFF 874 TRUCC 21 TOUCK 21
Partager