Powershell Get Hashtable Values - powershell

I've got this Hashtable with this values:
Name Value
---- -----
Bayas_palm_stem_A0311.jpg 1
Bayas_palm_stem_A0312.jpg 2
Bukit_Bangkong_area.tiff 1
BY_and_siblings_A0259.jpg 5
Cassava_camp_A0275.jpg 1
Children_A0115.jpg 6
cip_barau_kubak.jpg 1
How can i get only the Name and Value where Value is greater than 1 ?
I'm tryng with this code, but i'm doing something wrong!!!
$RT | Group-Object Name , Value | Where-Object {$RT.Values -gt 1}
Thanks a lot for any help.

Use $hashtable.GetEnumerator() to enumerate the individual name-value pairs in the hashtable:
$RT.GetEnumerator() |Where-Object {$_.Value -gt 1}
Beware that if you assign the resulting pairs to a variable, it's not longer a hashtable - it's just an array of individual name-value pairs.
To create a new hashtable with only the name-value pairs that filter through, do:
$RTFiltered = #{}
$RT.GetEnumerator() |Where-Object {$_.Value -gt 1} |ForEach-Object {$RTFiltered.Add($_.Name, $_.Value)}

Like this:
$RT.getenumerator() | Where-Object {$_.Value -gt 1}

Assuming you have a Hashtable defined like this.
$rt = #{
"Bayas_palm_stem_A0311.jpg " = 1
"Bayas_palm_stem_A0312.jpg " = 2
"Bukit_Bangkong_area.tiff " = 1
"BY_and_siblings_A0259.jpg " = 5
"Cassava_camp_A0275.jpg " = 1
"Children_A0115.jpg " = 6
"cip_barau_kubak.jpg " = 1
}
You can call GetEnumerator() which allows you to iterate through the Hashtable.
Once you've got an enumeration of the members, then your normal PowerShell value comparisons will work.
You can get values greater than 1 like this:
$rt.GetEnumerator() | ? Value -gt 1
Name Value
---- -----
BY_and_siblings_A0259.jpg 5
Children_A0115.jpg 6
Bayas_palm_stem_A0312.jpg 2

Related

PowerShell script to sort an array ascending order and return last value

I am having below PowerShell script which does not result in the sorting order I want.
$string = #("Project-a1-1", "Project-a1-10", "Project-a1-2", "Project-a1-5", "Project-a1-6", "Project-a1-8")
$myobjecttosort=#()
$string | ForEach{
$myobjecttosort+=New-Object PSObject -Property #{
'String'=$_
'Numeric'=[int]([regex]::Match($_,'\d+')).Value
}
}
$myobjecttosort | Sort-Object Numeric | Select Numeric,String | Format-Table -AutoSize
The output of the above script:
Numeric String
1 Project-a1-5
1 Project-a1-6
1 Project-a1-8
1 Project-a1-1
1 Project-a1-10
1 Project-a1-2
Required Output
1 Project-a1-1
2 Project-a1-2
3 Project-a1-5
4 Project-a1-6
5 Project-a1-8
6 Project-a1-10
Also, I want always output to be returned as the last value so here output would be Project-a1-10
Sort-Object accepts a script block allowing for a more robust sort. With that said, just like any other object in the pipeline, the objects are accessible via $PSItem, or $_. So, a quick way to go about this is splitting the string at the - selecting just the ending numerical digits, then casting [int] to the result to sort by.
$string = "Project-a1-1", "Project-a1-10", "Project-a1-2", "Project-a1-5", "Project-a1-6", "Project-a1-8"
$string |
Sort-Object -Property { [int]($_ -replace '^.*?(?=\d+$)') } |
% { $i = 1 } {
'{0} {1}' -f $i++, $_
}
The above yields:
1 Project-a1-1
2 Project-a1-2
3 Project-a1-5
4 Project-a1-6
5 Project-a1-8
6 Project-a1-10
Passing the sorted items to % (alias to Foreach-Object), we can then format a new string giving it an index # to each string starting at 1.

How to get Count of Values from a Hashtable per key in powershell

Currently I am able to get the list of values from a hashtable with the below cmdlet, but I would like get a count of values per key. Please lend me some advice, if this can be achieved using GetEnumerator method
$keys.GetEnumerator() | % {
[PSCustomObject]#{
key = $_.Value
}
}
My Hashtable $keys:
Name Value
---- -----
9 {G637A146}
-3 {F637A146, G637A146}
3 {F637A146, E637A146}
-2 {F637A146}
Expected Output Using GetEnumerator:
Key Value
---- -----
9 1
-3 2
3 2
-2 1
New Edit:
2. How to get the unique count of values as well?
My Hashtable $keys:
Name Value
---- -----
9 {G637A146, F637A146, J637A146}
-3 {F637A146, F637A146, G637A146, F637A146}
Expected Output Using GetEnumerator:
Key Value
---- -----
9 3
-3 2
Supposing your hashtable looks like this:
$keys = [ordered]#{
9 = 'G637A146'
-3 = 'F637A146', 'G637A146'
3 = 'F637A146', 'E637A146'
-2 = 'F637A146'
}
Then this should get you what you want:
$keys.GetEnumerator() | ForEach-Object {
[PSCustomObject]#{
Key = $_.Key
Value = ($_.Value).Count
}
}
Output:
Key Value
--- -----
9 1
-3 2
3 2
-2 1
Update
You could create a second hashtable where you keep track of the count values and only output if that vaue has not been seen before:
$seenThisBefore = #{}
$keys.GetEnumerator() | ForEach-Object {
$count = ($_.Value).Count
if (!$seenThisBefore.ContainsKey($count)) {
[PSCustomObject]#{
Key = $_.Key
Value = $count
}
$seenThisBefore[$count] = $true # add the count as key. The value here doesn't matter
}
}
I think you can cast the value to an array and then get the Count property.
So:
$keys.GetEnumerator() | % {
[PSCustomObject]#{
key = #($_.Value).Count
}
}
if I'm understanding your code correctly.
This is called the array sub-expression operator according to about_Arrays.
Since the comment response of the prior suggestion indicates that the format of the output for value isn't of some object but rather a string, then the value would need to be parsed.
Here's an example of how that might be done:
#('{a,b}' -replace '{', '' -replace '}', '' -split ',').Count
which produces the output of 2.
That just uses operators as documented on about_Operators

Powershell Get-Random with Constraints

I'm currently using the Get-Random function of Powershell to randomly pull a set number of rows from a csv. I need to create a constraint that says if one id is pulled, find the other ids that match it and pull their value.
Here is what I currently have:
$chosenOnes = Import-CSV C:\Temp\pk2.csv | sort{Get-Random} | Select -first 6
$i = 1
$count = $chosenOnes | Group-Object householdID
foreach ($row in $count)
{
if ($row.count -gt 1)
{
$students = $row.Group.Student
foreach ($student in $students)
{
$name = $student.tostring()
#...do something
$i = $i + 1
}
}
else
{
$name = $row.Group.Student
if($i -le 5)
{
#...do something
}
else
{
#...do something
}
$i = $i + 1
}
}
Example dataset
ID,name
165,Ernest Hemingway
1204,Mark Twain
1578,Stephen King
1634,Charles Dickens
1726,George Orwell
7751,John Doe
7751,Tim Doe
In this example, there are 7 rows but I'm randomly selecting 6 in my code. What needs to happen is when ID=7751 then I must return both rows where ID=7751. The IDs cannot not be statically set in the code.
Use Get-Random directly, with -Count, to extract a given number of random elements from a collection.
$allRows = Import-CSV C:\Temp\pk2.csv
$chosenHouseholdIDs = ($allRows | Get-Random -Count 6).householdID
Then filter all rows by whether their householdID column contains one of the 6 randomly selected rows' householdID values (PSv3+ syntax), using the -in array-containment operator:
$allRows | Where-Object householdID -in $chosenHouseholdIDs
Optional reading: performance considerations:
$allRows | Get-Random -Count 6 is not only conceptually simpler, but also much faster than $allRows | Sort-Object { Get-Random } | Select-Object -First 6
Using the Time-Command function to compare the performance of two approaches, using a 1000-row test file with 10 columns yields the following sample timings on my Windows 10 VM in Windows PowerShell - note that the Sort-Object { Get-Random }-based solution is more than 15(!) times slower:
Factor Secs (100-run avg.) Command TimeSpan
------ ------------------- ------- --------
1.00 0.007 $allRows | Get-Random -Count 6 00:00:00.0072520
15.65 0.113 $allRows | Sort-Object { Get-Random } | Select-Object -First 6 00:00:00.1134909
Similarly, a single pass through all rows to find matching IDs via array-containment operator -in performs much better than looping over the randomly selected IDs and searching all rows for each.
I tried sticking with your beginning and came up with this.
$Array = Import-CSV C:\test\StudtentTest.csv
$Array | Sort{Get-Random} | select -first 2 | %{
$id = $_.id
$Array | ?{$_.id -eq $id} | %{
$_
}
}
$Array will be your parsed CSV
We pipe in and sort by random select -first 2 (in this case)
Save the ID of the object into $id and then search the array for that ID and dispaly each that matches
If same ID does match you end up with something like
ID name
-- ----
7751 John Doe
7751 Tim Doe
1634 Charles Dickens

Get the name of the variable that contains the maximum value,if maximum value are 2 variables

The values of the variables are: a = 3, b = 6, and c = 2 d=6 The result should be the name of the variable that contains the maximum value— the text b&d i.e the result of maximum value.
$a = 3
$b = 6
$c = 2
$d = 6
$Variables = Get-Variable -name a,b,c,d
$Variables | Where { $_.Value -eq ($Variables | Measure-Object Value -Maximum).Maximum } | Select Name
Use Measure-Object to get the largest (maximum) value from the set of variables, then use Where-Object to filter the collection of variables to those with that maximum value and return their names via Select-Object.

Replace values in hashtable in PowerShell

I have a hashtable in PowerShell that looks like this:
$table = #{
1 = 3;
2 = 3;
5 = 6;
10 = 12;
30 = 3
}
I need to replace all "3" values with "4".
Is there a nice and clean way to do this without iterating over each pair and writing each one to a new hashtable?
Could the action with the same data be done easier if I'd use some other .NET collection class?
This throws exception that "Collection was modified":
$table.GetEnumerator() | ? {$_.Value -eq 3} | % { $table[$_.Key]=4 }
This adds another "Values" member to the object and breaks it:
$table.Values = $table.Values -replace 3,4
You can't modify the table while iterating over it, so do the iteration first and then do the updates. Just split your pipeline in two:
PS>$change = $table.GetEnumerator() | ? {$_.Value -eq 3}
PS>$change | % { $table[$_.Key]=4 }
PS>$table
Name Value
---- -----
30 4
10 12
5 6
2 4
1 4
The above answer didn't work for me and I couldn't fit this as a comment. The above single-lined answer didn't do anything. I am trying to change a single value to "Off" based on my hashtable.Key aka Name. Notice where I wrote $(backtick) is supposed to be a literal backtick, but it was messing up the code block. Here is my hashtable that is pulled from .\BeepVariables.txt.
Name Value
---- ----
$varAwareCaseSound "On"
$varEmailSound "On"
function SetHash2([string]$keyword, [string]$value){
$hash = #{}
$hash = (get-content .\BeepVariables.txt).replace(";"," $(backtick) n") | ConvertFrom-StringData
#($hash.GetEnumerator()) | ?{$_.key -like "*$keyword*"} | %{$hash[$_.value]=$value}
$hash
}
SetHash2 "aware" '"Off"'