Question
Amélioration de code
- Vincent
- Auteur du sujet
- Hors Ligne
- Nouveau membre
-
- Messages : 1
- Remerciements reçus 0
je suis nouveau sur ce forum, j'ai fais un petit programme powershel qui fonctionne mais que je ne trouve pas très esthétique et performant.
Il est fait à l'ancienne.
c'est mon premier programme en PS, donc j'ai beaucoup à apprendre.
le BUT suite à réception d'un fichier CSV, il me faut créer une aborescence de dossiers windows.
le fichier est structure comme SUIT:
CODE Libelle Niveau CODE -1
___________________________________________________
3005 , FRUIT , 2 , 3000
5000 , AGRUME , 3 , 3005
5005 , CITRON , 4 , 5000
5011 , ORANGE , 4 , 5000
5012 , MENDARINE , 4 , 5000
5013 , CLEMENTINE , 4 , 5000
5031 , ABRICOT , 4 , 3005
3006 , POMME , 2 , 3000
Le but est d'utiliser la notion de code -1 pour voir à quel niveau dans l'arborescence créer le dossier.
3000
|_> 3005
|_> 5000
|_> 5005
|_> 5011
|_> 5012
|_> 5013
|_> 5031
|_> 3006
Au départ je voulais faire une fois la lecture du fichier et le stocker dans un tableau à plusieurs dimensions mais ca n'a pas marché....
Voici mon code[code:1]clear
$fichier = Get-Content C:\toto.csv
cd 'C:\Arbo code'
Foreach ($line in $fichier) {
$line_splitted = $line.split(\",\"«»)
$CODE=$line_splitted[0]
$LIB=$line_splitted[1]
$NIV=$line_splitted[2]
$CODE1=$line_splitted[3]
if (($niv -eq \"1\"«») -and ($CODE -eq \"3000\" -or ($CODE -eq \"2010\"«»))){
Write-Host \"$CODE $LIB $NIV $CODE1\"
New-Item -Name \"$CODE\" -ItemType directory
$entite=$CODE
Foreach ($line in $fichier) {
$line_splitted = $line.split(\",\"«»)
$CODE=$line_splitted[0]
$LIB=$line_splitted[1]
$NIV=$line_splitted[2]
$CODE1=$line_splitted[3]
if ($CODE1 -eq $Entite){
New-Item -Name \"$Entite\$CODE\" -ItemType directory
$Categ=$CODE
Foreach ($line in $fichier) {
$line_splitted = $line.split(\",\"«»)
$CODE=$line_splitted[0]
$LIB=$line_splitted[1]
$NIV=$line_splitted[2]
$CODE1=$line_splitted[3]
if ($CODE1 -eq $Categ){
New-Item -Name \"$Entite\$Categ\$CODE\" -ItemType directory
$Esp=$CODE
Foreach ($line in $fichier) {
$line_splitted = $line.split(\",\"«»)
$CODE=$line_splitted[0]
$LIB=$line_splitted[1]
$NIV=$line_splitted[2]
$CODE1=$line_splitted[3]
if ($CODE1 -eq $Esp){
New-Item -Name \"$Entite\$Categ\$Esp\$CODE\" -ItemType directory
}
}
}
}
}
}
}
} [/code:1]
Si vous avez des idées
merci
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Wince34 écrit:
Je dois être fatigué, mais j'ai du mal à comprendre ton code et la construction autour de la relation \"code-1\"...
j'ai fais un petit programme powershell qui fonctionne mais que je ne trouve pas très esthétique et performant.
Donc ici, pour moi, l'esthétisme( qui selon moi n'a rien à faire dans le dev) et la performance est le cadet de mes soucis.
Wince34 écrit:
De le savoir me rassureIl est fait à l'ancienne.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Philippe
- Hors Ligne
- Modérateur
-
- Messages : 1778
- Remerciements reçus 21
j'ai fais un petit programme powershell qui fonctionne mais que je ne trouve pas très esthétique et performant.
Il est fait à l'ancienne.
déjà tu peut utilisé l'indentation, ca améliore l'esthétique et par là la lisibilité.
tu peut aussi utilisé IMPORT-CSV
ainsi tu pourra transformé cette partie de code :
[code:1] $line_splitted = $line.split(\",\"«»)
$CODE=$line_splitted[0]
$LIB=$line_splitted[1]
$NIV=$line_splitted[2]
$CODE1=$line_splitted[3]
[/code:1]
en
[code:1] $CODE=$line.code
$LIB=$line.libelle
$NIV=$line.niveau
$CODE1=$line.\"code-1\"
[/code:1]
MAIS ca impose deux chose :
1 - que la première ligne de label soit au même format que le reste du fichier (pas comme dans l'exemple)
2 - soit tu renomme le libelle \"CODE-1\", soit il faut faire très attention dans ton code car ca être mal interprété par powershell celons le code (en chaine de caractères ou en une soustraction)
autre chose simplifiable :
[code:1] $CODE=$line.code
$LIB=$line.libelle
$NIV=$line.niveau
$CODE1=$line.\"code-1\"
if (($niv -eq \"1\"«») -and ($CODE -eq \"3000\" -or ($CODE -eq \"2010\"«»))){
Write-Host \"$CODE $LIB $NIV $CODE1\"
New-Item -Name \"$CODE\" -ItemType directory
$entite=$CODE
[/code:1]
en
[code:1]
if (($line.niveau -eq \"1\"«») -and ($line.code -eq \"3000\" -or ($line.code -eq \"2010\"«»))){
Write-Host $line.code $line.libelle $line.niveau $line.\"code-1\"
New-Item -Name $line.code -ItemType directory
$entite=$line.code
[/code:1]
exemple de ce que pourrais etre le code apres simplification et adaptation du CSV
ATTENTION JE N'EST NI TESTE LE SCRIPT, NI VERIFIER LA SYNTAXE CA RESTE UN EXEMPLE DE PRESENTATION
[code:1]$fichier = import-csv C:\toto.csv
cd 'C:\Arbo code'
Foreach ($line in $fichier) {
if (($line.niveau -eq \"1\"«») -and ($line.code -eq \"3000\" -or ($line.code -eq \"2010\"«»))){
Write-Host $line.code $line.libelle $line.niveau $($line.\"code-1\"«»)
New-Item -Name $line.code -ItemType directory
$entite=$line.code
Foreach ($line in $fichier) {
if ($($line.\"code-1\"«») -eq $Entite){
New-Item -Name \"$Entite\$($line.code)\" -ItemType directory
$Categ=$line.code
Foreach ($line in $fichier) {
if ($line.\"code-1\" -eq $Categ){
New-Item -Name \"$Entite\$Categ\$($line.code)\" -ItemType directory
$Esp=$line.code
Foreach ($line in $fichier) {
if ($line.\"code-1\" -eq $Esp){
New-Item -Name \"$Entite\$Categ\$Esp\$($line.code)\" -ItemType directory
}
}
}
}
}
}
}
}[/code:1]
bon courage pour la suite, et revient vers nous pour d'éventuelle erreur ou pour d'autre question
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Effectivement, donc avant tout se préoccuper de la lisibilité.ça améliore l'esthétique et par là la lisibilité.
En regardant de plus près, tout en renommant, les champs on comprend mieux les données.
[code:1]
\"Parent\",\"Child\",\"Niveau\",\"Libelle\"
\"3000 \",\"3006\",\"2\",\"POMME\"
[/code:1]
J'ai eu la même approche que toi, mais je ne suis pas allé plus loin, car le code ne se faisait rien ou si peu.
J'ai donc recherché si qq avait déjà eu ce besoin, j'ai trouvé ceci . Ce qui dans un premier temps évite de coder des classes natives du framework.
La fonction est récursive et reste basée sur des boucles. Ce code n'est pas très efficace, mais pour qq centaines de lignes on peut s'en contenter.
De plus il ne peut créer que 100 niveaux, car Ps n'autorise que 100 appels récursifs.
Les données doivent utiliser des délimiteurs, et la suppression des espaces sur les champs Parent et Child ne serait pas de trop.
Après qq tests et adaptation, voici une autre solution :
[code:1]
@'
\"Parent\",\"Child\",\"Niveau\",\"Libelle\"
\"3000\",\"3006\",\"2\",\"POMME\"
\"3000\",\"3005\",\"2\",\"FRUIT\"
\"3005\",\"5000\",\"3\",\"AGRUME\"
\"3005\",\"5031\",\"4\",\"ABRICOT\"
\"5000\",\"5011\",\"4\",\"ORANGE\"
\"5000\",\"5013\",\"4\",\"CLEMENTINE\"
\"5000\",\"5005\",\"4\",\"CITRON\"
\"5000\",\"5012\",\"4\",\"MANDARINE\"
'@ > c:\temp\datas.csv
#'Facilite' la recherche
$DirectoryInfos=Import-csv c:\temp\datas.csv|Sort Parent,Child
function Set-ChildDirectory
{
#from powershell.cz/2012/11/27/generate-tree-structure/
[CmdletBinding()]
param(
[Parameter(Mandatory = $true,Position = 0)]
$InputObject,
[Parameter(Mandatory = $true,Position = 1)]
[string] $Id,
[Parameter()]
[int] $Shift = 0,
[Parameter()]
[string] $RootName
)
if ($PSBoundParameters.ContainsKey('RootName'))
{ $Name=$RootName }
$indent = ' ' * $shift
$Name=$Name+'\'+$ID
MD $Name > $null
$InputObject |
Where {
$_.Parent -eq $id
} |
ForEach {
Write-Debug (\"{0} {1}\" -f $indent, $_.Child)
Set-ChildDirectory -InputObject $InputObject -id $_.Child -shift $($shift+2)
}
}
$DirectoryInfos = Import-csv c:\temp\datas.csv|sort parent,Child
md 'C:\temp\TestDirByCode' -ea SilentlyContinue > $null
Set-Location 'C:\temp\TestDirByCode'
Set-ChildDirectory -InputObject $DirectoryInfos -Id 3000 -Root $Pwd
# C:\temp\TestDirByCode> show-tree #voir PSCX
# C:\temp\TestDirByCode
# \--3000
# |--3005
# | |--5000
# | | |--5005
# | | |--5011
# | | |--5012
# | | \--5013
# | \--5031
# \--3006
#
#ou Dir -rec |Select fullname
# C:\temp\TestDirByCode> dir -rec |select fullname
#
# FullName
#
# C:\temp\TestDirByCode\3000
# C:\temp\TestDirByCode\3000\3005
# C:\temp\TestDirByCode\3000\3006
# C:\temp\TestDirByCode\3000\3005\5000
# C:\temp\TestDirByCode\3000\3005\5031
# C:\temp\TestDirByCode\3000\3005\5000\5005
# C:\temp\TestDirByCode\3000\3005\5000\5011
# C:\temp\TestDirByCode\3000\3005\5000\5012
# C:\temp\TestDirByCode\3000\3005\5000\5013
[/code:1]
L'information Niveau n'est pas nécessaire ici.<br><br>Message édité par: Laurent Dardenne, à: 17/03/14 14:57
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Philippe
- Hors Ligne
- Modérateur
-
- Messages : 1778
- Remerciements reçus 21
je pense aussi la meme chose mais je connais pas l'ensemble du projetL'information Niveau n'est pas nécessaire ici.
de plus il me semble que une simple boucle avec quelque if ou un switch devrais suffire
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Le if je veux bien, voir le Where de la fonction Get-Child, mais pour le switch je suis curieux de voir çail me semble que une simple boucle avec quelque if ou un switch devrais suffire
Un switch est statique ce que n'est pas un arbre binaire, à moins que tu veuilles gérer un nombre de niveaux fixe...
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Entraide pour les débutants
- Amélioration de code