Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 09/08/2022, à 00:05

VroumH

Afficher la valeur la plus proche de la moyenne BASH

Bonjour ! !
J'ai besoin d'aide, j'ai deux listes
fichier1

1 -30.133 Orange
1  -6.576 Banane
1  -6.293 Pomme
1  -12.034 Abricot
1  -7,076 Mûre
2  -4,355 Pomme
2  -6,517 Banane
2  -6,355 Abricot
2  -3,502 Mûre

et j'ai les moyens
fichier2

1 -12.4224
2 -5.18225

Je me suis inspiré de la fonction find min() en python3

# create a list
ls = [3, 6, 7, 2, 1, 5]
# find min value using loop
min_val = ls[0]
for val in ls:
    if val < min_val:
        min_val = val
# display the min value
print(min_val)
#fichier2
#1  -12.4224
#2  -5.18225

#!/bin/bash
grep '1  ' fichier1  > temp2
awk '{ print $2 } ' temp2 > temp3
 
#temp3
#1 -30.133 Orange
#1 -6.576 Banane
#1 -6.293 Pomme
#1 -12.034 Abricot
#1 -7,076 Mûre
 
a=($(cat temp3 ))
b=($(cat fichier2 ))
minim=$(expr ${a[0]} - ${b[1]}) # comparaison de la première différence avec la moyenne
for i in $a; do # pour chaque valeur de la liste
	if [ $i - "${b[1]}" <= $minim ]; then # si la différence de i avec la moyenne est inférieur à la première différence alors minim devient le différence testée
		$minim=i
	fi	
	echo $i
done

Pour les groupes, je voudrais écrire : Pour le groupe 1, Abricot est le plus proche est le plus proche de la moyenne et pour le groupe 2, Pomme est le plus proche de la moyenne.

Hors ligne

#2 Le 09/08/2022, à 00:16

Watael

Re : Afficher la valeur la plus proche de la moyenne BASH


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#3 Le 09/08/2022, à 14:15

MixT

Re : Afficher la valeur la plus proche de la moyenne BASH

Après essayes en Python3 c'est déjà un langage plus "dynamique"

Hors ligne

#4 Le 09/08/2022, à 14:35

Watael

Re : Afficher la valeur la plus proche de la moyenne BASH

déjà, apprendre à rédiger un algorithme, avant de coder. hmm


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#5 Le 09/08/2022, à 15:35

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

Bonjour

Ouaih !, mais si on commence par dire qu'il faut faire ça en bash et que plus loin on utilise grep awk cat et autres programmes externes,
est-ce qu'il ne faudrait pas commencer par bien définir les règles du jeu ?

Hors ligne

#6 Le 09/08/2022, à 17:33

Tawal

Re : Afficher la valeur la plus proche de la moyenne BASH

Hello,

De toute façon, en bash, ça va être difficile.
Car il me semble bien que bash ne manipule que des entiers.


Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#7 Le 09/08/2022, à 18:30

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

… bash ne manipule que des entiers. …

Oui, mais rien n'empêche d'en faire des entiers en enlevant le point décimal, puis en ajoutant un ou deux zéros à la fin si nécessaire (suivant le nombre de décimales de la référence à comparer)
le but étant de comparer leur différences en fonction d'une référence, tout peut très bien être fait en pur bash sans avoir besoin de lancer une commande externe.

En utilisant les redirections et BASH_REMATCH ou simplement read,
on peut extraire les données contenues dans les fichiers
dont le tableau suivant :

tabl_1_Vals=( -30.133 -6.576 -6.293 -12.034 -7.076 )

Et ensuite :

michel@deb114x1t:~$ tabl_1_Vals=( -30.133 -6.576 -6.293 -12.034 -7.076 )
michel@deb114x1t:~$ tabl_1_Tmp=( ${tabl_1_Vals[*]/%/0} ) # Ajouter 1 zéro à la fin de chacun des éléments du tableau
michel@deb114x1t:~$ tabl_1_Tmp=( ${tabl_1_Tmp[*]//./} )  # Supprimer le point décimal qui est dans chacun des éléments du tableau
michel@deb114x1t:~$ echo ${tabl_1_Tmp[*]}
-301330 -65760 -62930 -120340 -70760
michel@deb114x1t:~$ 

Et voilà ci-dessus un tableau d'entiers prêt à êtres être soustraits et comparés par bash
à la référence -12.4224 à laquelle on aura enlevé le point décimal.

=======
Mais en fait, histoire d'économiser la RAM au cas où les fichiers de données seraient énormes,
on pourrait même se passer de tableau et lire les données une à une directement dans le fichier.

Dernière modification par MicP (Le 09/08/2022, à 20:50)

Hors ligne

#8 Le 09/08/2022, à 19:14

Tawal

Re : Afficher la valeur la plus proche de la moyenne BASH

Vas-y pour la lourdeur !
Tiens un tableau de nombre décimaux à traiter pour en faire la moyenne :

notes=( 1.024   3.2   5.6487   65.2   2.23548   10.77694 )

Soit on utilise un autre langage, ou alors on s'autorise des commandes externes (si on tient au script bash).
Au passage, awk serait bien indiqué à cette situation ...


Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#9 Le 09/08/2022, à 19:48

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

Tawal a écrit :

… Tiens un tableau de nombre décimaux à traiter pour en faire la moyenne :  …

Les moyennes ne sont pas à calculer …

Dans son message #1, VroumH a écrit :

… J'ai besoin d'aide, j'ai deux listes
fichier1

et j'ai les moyens
fichier2

…puisqu'elles sont données dans fichier2

Mais si tu veux vraiment un résultat approximatif de la moyenne (ci dessous, je ne t'ai mis que les 64 premières décimales) wink ,
tu peux toujours utiliser la commande externe bc

michel@deb114x1t:~$ notes=( 1.024   3.2   5.6487   65.2   2.23548   10.77694 )
michel@deb114x1t:~$ notesTmp="${notes[@]/#/ + }"; BC_LINE_LENGTH=0 bc <<< "scale=64; ${notesTmp/+ } / ${#notes[@]}"
79.1043366666666666666666666666666666666666666666666666666666666666
michel@deb114x1t:~$ 

=======
L'algorithme que je propose (sans tableaux) :

Pour plus de clarté, je vais appeler :
- fichDonnees   le fichier nommé fichier1
- fichMoyennes le fichier nommé fichier2

lire fichMoyennes ligne par ligne tant qu'il y aura des lignes à lire
    en extrayant un numeroMoyenne et valeurMoyenne associée

    initialiser valeurMin à valeur du même nombre de chiffres + 1 chiffre tous à 9 (=> valeur maxi possible en fonction du nombre de chiffres dans la valeur)
    initialiser chaineMin à chaîne vide
    Lire fichDonnees ligne par ligne tant qu'il y aura des lignes à lire (Dans l'exemple, les numeroDonnee sont rangés consécutivement dans l'ordre, mais autant tout lire au cas où)
        en extrayant le numeroDonnee, la valeurDonnee, et la chaineDonnee associée
        si numeroDonnee est égal à numeroMoyenne, alors
            difference = ( valeurDonnee - valeurMoyenne )
            si difference est inférieur à valeurMin alors valeurMin = difference et chaineMin = chaineDonnee
    fin de lecture de fichDonnees => sortie de la chaineMin et du numeroMoyenne associé

fin de lecture de fichMoyennes

Comme tout ça va se passer dans bash sans avoir à lancer de commande(s) externe(s), ça devrait être assez rapide.

=======
NOTE : Ce n'est pas le cas dans le sujet donné, mais si les valeurs numériques étaient trop grandes (dépassement de capacité de valeur numérique pour bash),
          alors il faudrait prévoir de faire des calculs de différence et comparaison
          chiffre par chiffre <=> caractère par caractère <=> travailler sur les chaînes de caractères représentant les nombres.

Dernière modification par MicP (Le 10/08/2022, à 00:01)

Hors ligne

#10 Le 09/08/2022, à 20:24

Tawal

Re : Afficher la valeur la plus proche de la moyenne BASH

Ah oui, j'étais parti sur le calcul des moyennes.
Mais quand même, je pense qu'avec awk, ce serait plus facile.
Lecture des données, tri, comparaison et affichage, c'est un peu son rôle non ?


Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#11 Le 09/08/2022, à 20:39

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

Oui, je suis sûr qu'avec les fonctions mathématiques superbes d'awk, on pourrait même calculer la moyenne,
et en plus, on pourrait même se passer du shell bash

Mais le titre de ce fil de discussion est : Afficher la valeur la plus proche de la moyenne BASH

Dernière modification par MicP (Le 09/08/2022, à 20:42)

Hors ligne

#12 Le 09/08/2022, à 20:48

Tawal

Re : Afficher la valeur la plus proche de la moyenne BASH

J'aurais tendance à diriger le demandeur vers un type de solution plus adaptée.
Et en plus question ressource/rapidité, awk s'en sortirai bien mieux que bash dans ce cas là.

Dernière modification par Tawal (Le 09/08/2022, à 20:48)


Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !

Hors ligne

#13 Le 09/08/2022, à 21:33

Watael

Re : Afficher la valeur la plus proche de la moyenne BASH

MicP a écrit :

Les moyennes ne sont pas à calculer …

Dans son message #1, VroumH a écrit :

… J'ai besoin d'aide, j'ai deux listes
fichier1

et j'ai les moyens
fichier2

…puisqu'elles sont données dans fichier2

c'est évidemment très maladroit, puisque lorsque le fichier "source" changera, il faudra calculer en externe les moyennes. hmm

considérons qu'on a un seul fichier de données, et que les moyennes sont à calculer dans le script.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#14 Le 10/08/2022, à 00:07

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

Watael a écrit :

…considérons qu'on a un seul fichier de données, et que les moyennes sont à calculer dans le script. …

Une ébauche d'algorithme pour le calcul de la moyenne en pur bash :

nbrBits=$(while [[ $((valeurBin**exposant)) -gt 0 ]]; do $((exposant=exposant+1)); done; echo $((exposant)))   # il y a un bit qui est utilisé pour le signe (positif ou négatif)
maxValuePosBash=$(((2**nbrBits)-1)); maxValueNegBash=$((2**nbrBits))
echo "Sur cette machine et avec ce système d'exploitation, bash peut utiliser un entier signé allant de $maxValueNegBash à +$maxValuePosBash"

Il faudra que chacune des valeurs et la somme des valeurs restent dans ces limites
et que le nombre d'éléments soit inférieur ou égal à la valeur positive maxi : maxValuePosBash

- Extraire du fichier la série des valeurs dont il faudra calculer la moyenne
- Vérifier que le nombre d'éléments est inférieur ou égal à la valeur positive maxi : maxValuePosBash
    sinon, c'est cuit => on s'arrête là

Pour transformer chacune des valeurs en entier signé, il faudra :
- Pour chacune des valeurs, s'il n'existe pas de point décimal dans la valeur alors ajouter un point décimal à la fin de la valeur
- Égaliser le nombre de décimales des valeurs en ajoutant au besoin des zéros à la fin
- Supprimer le point décimal dans chaque valeur
- Vérifier que chacune   des valeurs reste dans les limites autorisées et ajuster au besoin en ajoutant/supprimant des chiffres à la fin de chacune des valeur
- Vérifier que la somme des valeurs reste dans les limites autorisées et ajuster au besoin en ajoutant/supprimant des chiffres à la fin de chacune des valeur

Je reprendrai ça plus tard…

Dernière modification par MicP (Le 10/08/2022, à 00:13)

Hors ligne

#15 Le 10/08/2022, à 03:52

Watael

Re : Afficher la valeur la plus proche de la moyenne BASH

ça ne me gêne pas d'utiliser une programme externe pour pallier les limites du shell.
contrairement aux expr, cut, grep, awk... j'utilise sans souci bc, surtout quand je vois les détours et précautions à prendre pour calculer des décimaux.


Connected \o/
Welcome to sHell. · eval is evil.

Hors ligne

#16 Le 10/08/2022, à 07:26

MicP

Re : Afficher la valeur la plus proche de la moyenne BASH

Bonjour

Il faudra aussi préciser dans le sujet ce qu'il faut faire dans les deux cas suivants :

- il se pourrait que le calcul de la moyenne donne un résultat dont le nombre de décimales est infini
   il faudra donc que le nombre de décimales à prendre en compte soit définit dans le sujet

- Il se pourrait que la valeur absolue de la différence avec la moyenne donne le même résultat pour plusieurs valeurs
    il faudra donc décider de ce qu'il faut faire dans ce cas là

Dernière modification par MicP (Le 10/08/2022, à 07:27)

Hors ligne

#17 Le 10/08/2022, à 14:54

LeoMajor

Re : Afficher la valeur la plus proche de la moyenne BASH

salut,
valeur approchée,

:~$ python2 -c 'print round(5.76543, 2)'
5.77
:~$ gbs3 -e 'print round(5.76543, -2)'
5,77
:~$ gbs3 -e "dim f as integer[]=[1900, 1923, 1945, 1960, 1956, 1999, 2020 ]: dim sum as float: for i as integer=0 to f.max: sum+=f[i]: next: print sum/f.count,round(sum/f.count), round(sum/f.count,2),round(sum/f.count,1), round(sum/f.count,-1), round(sum/f.count,-5)"
1957,57142857143	1958	2000	1960	1957,6	1957,57143

:~$ gbs3 -e "dim f as float[]=[-30.133, -6.576, -6.293, -12.034, -7.076]: dim sum as float: for i as integer=0 to f.max: sum+=f[i]: next: print sum/f.count,round(sum/f.count), round(sum/f.count,2), round(sum/f.count,1), round(sum/f.count,-1), round(sum/f.count,-3)"
-12,4224	-12	0	-10	-12,4	-12,422

edit: la valeur de la liste la plus proche de la moyenne

:~$ gbs3 -e "dim f as float[]=[6.024, 3.2, 5.6487, 65.2, 23.23548, 15.34]: dim moy as float: for i as integer=0 to f.max: print i,f[i]: moy+=f[i]: next: moy=round(moy/f.count,-5): print moy,\"moyenne\": f.add(moy): f.sort(): dim sup as float=(f[f.find(moy)+1] -f[f.find(moy)]): dim inf as float=(f[f.find(moy)] -f[f.find(moy)-1]): print if(sup>inf, \"+ proche \" & f[f.find(moy)-1], \"+ proche \" & f[f.find(moy)+1]) "
0	6,024
1	3,2
2	5,6487
3	65,2
4	23,23548
5	15,34
19,7747	moyenne
+ proche 23.23548

Dernière modification par LeoMajor (Le 10/08/2022, à 18:17)

Hors ligne

#18 Le 16/08/2022, à 13:35

VroumH

Re : Afficher la valeur la plus proche de la moyenne BASH

Merci de tous vos conseils smile

Hors ligne