I have two hash tables and I need to compare them. Let me explain my problem :
[hashtable]$User = #{
"Jack" = "AdminLA, AdminUSA";
"John" = "AdminAustralia";
"Sarah" = "AdminIceland";
"Arnold" = "AdminUSA";
"Maurice" = "AdminAustralia, AdminCanada";
}
[hashtable]$Profil = #{
"AdminLA" = "P1";
"AdminIceland" = "P2";
"AdminUSA" = "P3";
"AdminCanada" = "P4";
"AdminAustralia" = "P5" ;
"AdminCroatia" = "P6";
}
I want to have this kind of result :
Key Value
--- -----
Jack P1, P3
John P5
Sarah P2
Arnold P3
Maurice P5, P4
Actually, I have only one value (I haven't succeeded to have multiple values. For example Jack must have P1 and P3 and I have only P1).
How can I fix it?
I have already tried:
$User.GetEnumerator() | select Key, #{n='Value'; e={$Profil[$_.Value]}}
and
$User.GetEnumerator() | %{[PSCustomObject]#{aKey=$_.Key;bValue=$Profil[$_.Value]}}
Any idea?
Use this expression
$User.GetEnumerator() | Select-Object Key, #{name='Value'; expression={($_.Value -split ", " | Foreach-Object {$Profil[$_]}) -join ", "}}
This basically creates an array of input values, get the values from $Profil for each element and then creates a string from these values.
Related
In filename "name" like '10_m1_m2_const_m1_waves_20_90_m2_waves_90_20_20200312_213048' I need to separate
'10_m1_m2_const_m1_waves_20_90_m2_waves_90_20' from '20200312_213048'
name_sep = split(name,"_");
sep = '_';
name_join=[name_sep{1,1} sep name_sep{2,1} sep .....];
is not working, because a number of "_" are variable.
So I need to move a file:
movefile([confpath,name(without 20200312_213048),'.config'],[name(without 20200312_213048), filesep, name, '.config']);
Do you have any idea? Thank you!
Maybe you can try regexp to find the starting position for the separation:
ind = regexp(name,'_\d+_\d+$');
name1 = name(1:ind-1);
name2 = name(ind+1:end);
such that
name1 = 10_m1_m2_const_m1_waves_20_90_m2_waves_90_20
name2 = 20200312_213048
Or the code below with option tokens:
name_sep = cell2mat(regexp(name,'(.*)_(\d+_\d+$)','tokens','match'));
which gives
name_sep =
{
[1,1] = 10_m1_m2_const_m1_waves_20_90_m2_waves_90_20
[1,2] = 20200312_213048
}
You can use strfind. Either if you have a key that is always present before or after the point where you want to split the name:
nm = '10_m1_m2_const_m1_waves_20_90_m2_waves_90_20_20200312_213048';
key = 'waves_90_20_';
idx = strfind(nm,key) + length(key);
nm(idx:end)
Or if you know how may _ are in the part that you want to have:
idx = strfind(nm,'_');
nm(idx(end-2)+1:end)
In both cases, the result is:
'20_20200312_213048'
As long as the timestamp is always at the end of the string, you can use strfind and count backwards from the end of the string:
name = '10_m1_m2_const_m1_waves_20_90_m2_waves_90_20_20200312_213048';
udscr = strfind(name,'_');
name_date = name(udscr(end-1)+1:end)
name_meta = name(1:udscr(end-1)-1)
name_date =
'20200312_213048'
name_meta =
'10_m1_m2_const_m1_waves_20_90_m2_waves_90_20'
I have a hash array as such:
$weeklyStats[$RecipientName][$weekNr][$total]
Which is created in a loop as such:
$weeklyStats = #{}
$weekNr = get-date -UFormat %V
ForEach ($RecipientName in $MailTraffic.keys)
{
$weeklyStats[$RecipientName] = #{}
$weeklyStats[$RecipientName][$weekNr] = #{}
$weeklyStats[$RecipientName][$weekNr]['Total'] = 0
$weeklyStats[$RecipientName][$weekNr]['Sent'] = 0
$weeklyStats[$RecipientName][$weekNr]['Received'] = 0
foreach($item in $MailTraffic[$RecipientName].keys)
{
weeklyStats[$RecipientName][$weekNr]['Total'] =+ 1
if $MailTraffic[$RecipientName]['transaction'] == "Sent"
{
$weeklyStats[$RecipientName][$weekNr]['Sent'] =+ 1
}
else
{
$weeklyStats[$RecipientName][$weekNr]['Received'] =+ 1
}
}
}
I don't know how to 'dump' a variable in Powershell but here is the contents in json:
{
"mike": {
"11": {
"Total": 411,
"Sent": 21,
"Received":390,
}
},
"peter": {
"11": {
"Total": 751,
"Sent": 51,
"Received":700,
}
},
"frank": {
"11": {
"Total": 620,
"Sent": 20,
"Received":600,
}
},
}
I want to print out the keys and values in descending order of the $total.
I can only find examples how to do it if the hash table is only one level deep.
The intended output would be:
Name Total Received Sent
----- ----- ----- -----
peter 751 700 51
frank 620 600 20
mike 411 390 21
Sort by referencing the Keys property of the inner hashtable, then assign to a new [ordered] dictionary:
$sorted = [ordered]#{}
$stats.GetEnumerator() |Sort-Object {
# Sort by first key from each inner hashtable
$_.Value.Keys |Select -First 1
} -Descending |ForEach-Object {
# re-assign to our ordered dictionary
$sorted[$_.Key] = $_.Value
}
$sorted now contains your new sorted dictionary
Most PowerShell cmdlets are intended to handle (stream!) [PSObject] type (which includes a [PScustomerObject] type) lists for input and output.
(To understand the difference see e.g. Difference between PSObject, Hashtable, and PSCustomObject).
Nested hash tables are difficult to maintain and handle in PowerShell (see also: Powershell Multidimensional Arrays) because PowerShell is optimized for streaming which is rather difficult with cascaded objects, therefore I recommend you convert you nested hashtable in a (rather flat) [PScustomerObject] list, something like:
$PSStats =
ForEach ($name in $Stats.Keys) {
ForEach ($weekNr in $_.Keys) {
ForEach ($total in $_.Keys) {
[pscustomobject]#{name = $name; weekNr = $weekNr; total = $total}
}
}
}
Once you have converted it into PSCustomObject list, you can easily sort it and display the results:
$PSStats | Sort-Object Total
I would just create a custom object from your hash tables and then sort on the Title property:
# Creation of $mailtraffic
$mailtraffic = #{'Mike' = #{'Total' = 411; 'Sent' = 21; 'Received' = 390};'Peter' = #{'Total' = 751; 'Sent' = 51; 'Received' = 700};'Frank' = #{'Total' = 620; 'Sent' = 20; 'Received' = 600}}
# Sorting Code
$mailtraffic.GetEnumerator() |
Select #{n='Name';e={$_.Key}},#{n='Total';e={$_.Value.Total}},#{n='Received';e={$_.Value.Received}},#{n='Sent';e={$_.Value.Sent}} |
Sort Total -Descending
Im looking for a data structure/cmdlet that will allow me to add multiple values to a single key in Powershell.
My data would ideally look like this:
KEY-------------------------- VALUES
HOSTNAME1-------------DATABASE1,DATABASE2,DATABASE3
HOSTNAME2-------------DATABASE1,DATABASE2
etc...
I thought a hashtable would do the trick, but I'm unable to do the following:
$servObjects = #{}
$servObjects.Add("server1", #())
$servObjects.get_item("server1") += "database1"
This yields an empty array when I try:
$servObjects.get_item("server1")
I have also tried to do the following, hoping that powershell would understand what I want:
$servObjects2 = #{}
$servObjects2.add($servername, $databasename)
This will unfortunately yield a duplicate key exception
Thanks for any and all input
You basically want a hash table with values that are arrays. You don't have to use $hashtable.get_item or .add
$myHashTable = #{} # creates hash table
$myHashTable.Entry1 = #() #adds an array
$myHashTable.Entry1 += "element1"
$myHashTable.Entry1 += "element2"
This results in the following output:
$myHashTable
Name Value
---- -----
Entry1 {element1, element2}
$myHashTable.Entry1
element1
element2
If you have your data in an array you can group the array and convert to a hash table:
$ary = #()
$ary = $ary + [PSCustomObject]#{RowNumber = 1; EmployeeId = 1; Value = 1 }
$ary = $ary + [PSCustomObject]#{RowNumber = 2; EmployeeId = 1; Value = 2 }
$ary = $ary + [PSCustomObject]#{RowNumber = 3; EmployeeId = 2; Value = 3 }
$ary = $ary + [PSCustomObject]#{RowNumber = 4; EmployeeId = 2; Value = 4 }
$ary = $ary + [PSCustomObject]#{RowNumber = 5; EmployeeId = 3; Value = 5 }
$ht = $ary | Group-Object -Property EmployeeId -AsHashTable
$ht is then:
Name Value
---- -----
3 {#{RowNumber=5; EmployeeId=3; Value=5}}
2 {#{RowNumber=3; EmployeeId=2; Value=3}, #{RowNumber=4; EmployeeId=2; Value=4}}
1 {#{RowNumber=1; EmployeeId=1; Value=1}, #{RowNumber=2; EmployeeId=1; Value=2}}
In your original example, instead of writing
$servObjects.get_item("server1") += "database1"
you had written
$servObjects.server1 += "database1"
it would have worked.
I'm very new to PowerShell, but I prefer to use
$servObjects.Add("key",#())
over
$servObjects.key = #())
because the .Add will throw a duplicate exception if the key is already present in the hashtable, whereas the assignment will replace an existing entry with a new one. For my purposes, I have found that the implicit replacement is (more often than not) an error, either in my logic, or an anomaly in the input data that needs to be handled.
If you know the value at creation time, it would be clearer this way :
[hashtable]$hash = #{
HOSTNAME1 = #(DATABASE1, DATABASE2, DATABASE3);
HOSTNAME2 = #(DATABASE1, DATABASE2);
}
Which will get you the following :
Name Value
---- -----
HOSTNAME2 {DATABASE1, DATABASE2}
HOSTNAME1 {DATABASE1, DATABASE2, DATABASE3}
I have a theoretical problem - how to reference a hash table during its initialization, for example, to compute a member based other already stated members.
Remove-Variable myHashTable -ErrorAction Ignore
$myHashTable =
#{
One = 1
Two= 2
Three = ??? # following expressions do not work
# $This.One + $This.Two or
# $_.One + $_.Two
# $myHashTable.One + $myHashTable.Two
# ????
}
$myHashTable.Three -eq 3 # make this $true
Any ideas how to do it? Is it actually possible?
Edit:
This was my solution:
$myHashTable =
#{
One = 1
Two= 2
}
$myHashTable.Three = $myHashTable.One + $myHashTable.Two
This won't be possible using the object initializer syntax I'm afraid. While it is possible to use variables, you'll have to compute the values before creating the object.
I cannot recommend this, but you can iterate the initializer twice or more:
(0..1) | %{
$a = #{
One = 1
Two = $a.One + 1
}
}
(0..2) | %{
$b = #{
One = 1
Two = $b.One + 1
Three = $b.Two + 1
}
}
Make sure all calculations are idempotent, i.e. do not depend on a number of iterations.
You can also recur to this...
sometimes when the hashtable is very long
and can be defined only in 2 or three recurrences...
works fine:
$AAA = #{
DAT = "C:\MyFolderOfDats"
EXE = "C:\MyFolderOfExes"
}
$AAA += #{
Data = $AAA.DAT + "\#Links"
Scripts = $AAA.EXE + "\#Scripts"
ScriptsX = $AAA.EXE + "\#ScriptsX"
}
Note in the second part we are just adding ( += ) more items to the first part... but now... we can refer the items in first part
of the hashtable
I've programmed a summary chart, and I'm trying to add a "Totals" line that will sum up three columns. The exercise is comprised of a number of questions, and the participant can increase, decrease or maintain a certain dollar amount. The column B total shows the initial values (where the slider starts off on). The column C shows the amount the participant either increased or decreased and the last column shows the resulting dollar amount. (B + C)
Here's an example of the summary chart
Column A --- B ------ C------ D
Question 1 | 100$ | +28$ | 128$ |
Question 2 | 150$ | (10$) | 140$ |
Totals ------| 250$ | +18$ | 268$ |
So far I've been able to program the totals for column B and D, but I can't figure out how to show a total for column C.
class window.CustomSimulator extends window.TaxSimulator
constructor: (#options = {}) ->
super
#updateTable()
update: ->
super
#updateTable()
updateTable: ->
self = this
$table = $('<table class="table table-condensed"><thead><tr><th>Category</th><th>Before</th><th>Your Choice</th><th>After</th></tr></table>')
$tbody = $('<tbody></tbody>')
before_total = 0
after_total = 0
#scope.find('.slider').each ->
$this = $(this)
$parents = $this.parents('tr')
category = $parents.find('.header').clone().children().remove().end().text().replace(/How would you adjust service levels and property tax funding for /, '').replace('?', '')
before = self.tipScaler($this, $this.data('initial'))
your_choice = $parents.find('.value').text()
after = $parents.find('.tip-content').text()
if $parents.find('.key').text() == 'Decrease:'
css_class = 'decrease'
your_choice = "(#{your_choice})"
else
css_class = 'increase'
$tr = $("""<tr><td>#{category}</td><td>#{before}</td><td class="table-#{css_class}">#{your_choice}</td><td>#{after}</td></tr>""")
$tbody.append($tr)
before_total += parseFloat(before.replace('$', ''))
after_total += parseFloat(after.replace('$', ''))
before_total = SimulatorHelper.number_to_currency(before_total, precision: 2, strip_insignificant_zeros: true)
after_total = SimulatorHelper.number_to_currency(after_total, precision: 2, strip_insignificant_zeros: true)
$("""<tfoot><tr><th>Totals</th><th>#{before_total}</th></th><th><th>#{after_total}</th></tr></tfoot>""").appendTo($table)
$table.append($tbody)
$('#summary-table').html($table)
I'm pretty new at this so I'm not sure if this is enough information.
Thanks!