Je me demande si quelqu'un pourrait m'aider. Le problème est que j'essaye d'importer, de regrouper, de faire la somme et d'exporter un CSV. Le problème est que mon CSV a un nombre inconnu de colonnes du format suivant.
GroupA, GroupB, GroupC, ValueA, ValueB, ValueC, ValueD ...
GroupA, B et C sont constants et les champs que je souhaite regrouper - je connais à l'avance les noms de ces champs. Le problème est qu'il y a un nombre inconnu de colonnes Value - que je veux toutes additionner (et je ne connais pas les noms à l'avance.)
Je suis à l'aise pour faire fonctionner ce code si je sais le nom des champs de valeur et ont un nombre fixe de champs de valeur. Mais j'ai du mal à obtenir du code pour les noms et le nombre de colonnes inconnus.
GroupA, GroupB, Value A Sam, Apple, 30 Sam, Orange, 50 Ian, Apple, 15
Exemple de données d'entrée -
GroupA, GroupB, Value A Sam, Apple, 10 Sam, Apple, 20 Sam, Orange, 50 Ian, Apple, 15
Données de sortie -
$csvImport = import-csv 'C:\input.csv'
$csvGrouped = $csvImport | Group-Object -property GroupA,GroupB,GroupC
$csvGroupedFinal = $csvGrouped | Select-Object @{Name = 'GroupA';Expression={$_.Values[0]}},
@{Name = 'GroupB';Expression={$_.Values[1]}},
@{Name = 'GroupC';Expression={$_.Values[2]}},
@{Name = 'ValueA' ;Expression={
($_.Group|Measure-Object 'ValueA' -Sum).Sum
}}
$csvGroupedFinal | Export-Csv 'C:\output.csv' -NoTypeInformation
3 Réponses :
Après l'importation, ce script divise les propriétés (colonnes) en Groupes / Valeurs
L'ordre des entrées est maintenu avec un Select-Object final
Groups ValueA ValueB ValueC ------ ------ ------ ------ Sam, Apple 30 4 20 Sam, Orange 50 4 5 Ian, Apple 15 3 3
Avec cet exemple de fichier d'entrée
Groups ValueA ValueB ------ ------ ------ Sam, Apple 30 40 Sam, Orange 50 75 Ian, Apple 15 20
Exemple de sortie pour n'importe quel nombre de groupes et de valeurs p >
GroupA GroupB ValueA ValueB ------ ------ ------ ------ Sam Apple 10 15 Sam Apple 20 25 Sam Orange 50 75 Ian Apple 15 20
Sans aucune modification de code, il traite également les données de Hassans.
## Q:\Test\2019\01\17\SO_54237887.ps1
$csvImport = Import-Csv '.\input.csv'
$Cols = ($csvImport[0].psobject.Properties).Name
# get list of group columns by name and wildcard
$GroupCols = $Cols | Where-Object {$_ -like 'Group*'}
# a different approach would be to select a number of leading columns
# $GroupCols = $Cols[0..1]
$ValueCols = $Cols | Where-Object {$_ -notin $GroupCols}
$OutCols = ,'Groups' + $ValueCols
$csvGrouped = $csvImport | Group-Object $GroupCols | ForEach-Object{
$Props = @{Groups=$_.Name}
ForEach ($ValCol in $ValueCols){
$Props.Add($ValCol,($_.Group|Measure-Object $ValCol -Sum).Sum)
}
[PSCustomObject]$Props
}
$csvGrouped | Select-Object $OutCols
Merci pour votre réponse. C'est une boucle de plusieurs valeurs (d'un nombre inconnu) avec lesquelles je lutte, si cela ne vous dérange pas de le démontrer.
Désolé. J'ai modifié votre réponse au lieu de ma propre réponse. Espérons que l'examen par les pairs voit cette erreur et annule la modification. Vous pouvez également rajouter votre réponse.
@SamDolbear crée maintenant dynamiquement les propriétés de [PSCustomObject]
Merci pour la modification, ressemble exactement à ce dont j'ai besoin!
Donc, un vote positif ou une réponse partagée ou une réponse de changement pour ce qui précède?
@JosefZ Réécrit le script pour utiliser la méthode initiale .PSObject.Properties qui ne classe PAS les propriétés par ordre alphabétique. Au lieu de vous fier au Groupe faire partie des colonnes, vous pouvez maintenant utiliser alternativement les premières n colonnes pour le regroupement.
script1.ps1
PS D:\coding> .\script1.ps1 GroupA GroupB Sum ------ ------ --- Sam Apple 54 Sam Orange 59 Ian Apple 21
input.csv
GroupA, GroupB, ValueA, ValueB, ValueC Sam, Apple, 10, 1, 10 Sam, Apple, 20, 3, 10 Sam, Orange, 50, 4, 5 Ian, Apple, 15, 3, 3
OUTPUT
Import-Csv 'input.csv' | `
Group-Object -Property GroupA,GroupB | `
% {$b=$_.name -split ', ';$c=($_.group | `
Measure-Object -Property Value* -Sum).Sum;
[PScustomobject]@{GroupA=$b[0];
GroupB=$b[1];
Sum=($c | Measure-Object -Sum).Sum }}
p>
Salut, merci pour votre réponse. Malheureusement, cela fait la même chose que le code de ma question, mais ne fonctionnerait pas si je veux étendre cela pour un nombre inconnu de `` valeurs '' (valeur A, valeur B valeur C ....) - ce qui devrait être déterminé dynamiquement.
@SamDolbear Voir ma réponse modifiée ci-dessus. Différent de la réponse acceptée mais peut-être utile pour le moment ou pour une autre fois ou peut-être par quelqu'un d'autre.
Le script suivant devrait fonctionner. Faites attention à la variable $ FixedNames :
$csvImport = @" Group A,Group B,Value A,Value B sam,apple,10,1 sam,apple,20, sam,orange,50,5 ian,apple,15,51 "@ | ConvertFrom-Csv
Testé de la même façon pour
$csvImport = @"
Group A,Group B,Value A
sam,apple,10
sam,apple,20
sam,orange,50
ian,apple,15
"@ | ConvertFrom-Csv
$FixedNames = @('Group A', 'Group B', 'Group C')
# $aux = ($csvImport|Get-Member -MemberType NoteProperty).Name ### sorted (wrong)
$aux = ($csvImport[0].psobject.Properties).Name ### not sorted
$auxGrpNames = @( $aux | Where-Object {$_ -in $FixedNames})
$auxValNames = @( $aux | Where-Object {$_ -notin $FixedNames})
$csvGrouped = $csvImport | Group-Object -property $auxGrpNames
$csvGroupedFinal = $csvGrouped |
ForEach-Object {
($_.Name.Replace(', ',','), (($_.Group |
Measure-Object -Property $auxValNames -Sum
).Sum -join ',')) -join ','
} | ConvertFrom-Csv -Header $aux
$csvGroupedFinal
ainsi que pour plus données complexes de l'en-tête Groupe A, Groupe B, Groupe C, Valeur A, Valeur B .
Modifier mis à jour selon le Commentaire de LotPings bénéfique . p>
Excellent merci! On dirait ce dont j'ai besoin! Merci encore! Testera à son retour au travail.
@SamDolbear Malheureusement, la solution dépend des noms de colonnes dans le CSV d'origine: le tableau Get-Member -MemberType NoteProperty semble être trié par la propriété Name . Par conséquent, mieux vaut obtenir les variables $ aux , $ auxGrpNames et $ auxValNames d'une autre manière (par exemple, en analysant la ligne d'en-tête)! Astuce: lisez l'en-tête d'une variable en utilisant Get-Content , divisez-le en la variable $ aux .
Vous pouvez utiliser la méthode non triée $ aux = ($ csvImport [0] .psobject.Properties) .Name pour obtenir l'en-tête. Et d'avoir les trois premiers pour trier $ auxGrpNames = $ aux [0..2]
Vous devez fournir des exemples de données d'entrée et de sortie attendue. Je ne sais pas si vous voulez additionner les colonnes par ligne ou les totaux de toutes les lignes par colonne.
Les totaux de toutes les lignes par colonne ont donné des exemples de données. Je vous remercie!
Devez-vous utiliser PowerShell? Cela peut être facilement fait en python.
Malheureusement, je ne peux pas utiliser Python, je suis dans un environnement de travail restreint.