PowerShell accessing data from hashtable inside hashtable - powershell

I have 5 hash tables:
$Monday = #{RUG = "";NRH1 = "";NRH2 = "";ELM = "";BAGVAGT = ""}
$Tuesday = #{RUG = "";NRH1 = "";NRH2 = "";ELM = "";BAGVAGT = ""}
$Wednesday = #{NRH1 = "";NRH2 = "";ELM = "";BAGVAGT = ""}
$Thursday = #{NRH1 = "";NRH2 = "";ELM = "";BAGVAGT = ""}
$Friday = #{NRH1 = "";NRH2 = "";ELM = ""}
That get filled with data. And I can get data out from these either one at at time with $Monday.RUG or all with $Monday | out-string. No problem there.
I'm going to combine those in another hash table 100 times with different data.
So it will be like this:
$Week = #{
1 = #{mo=$Monday;tu=$Tuesday;we=$Wednesday;th=$Thursday;fr=$Friday;val=$value}
2 = #{mo=$Monday;tu=$Tuesday;we=$Wednesday;th=$Thursday;fr=$Friday;val=$value}
}
And so on, until I have 100 different weeks with different values (value will be a calculated number)
But the question is. How do I access the items in the hashtables inside the $week hashtable?
Is there a direct way like $week.1.mo ? or do you need to use a loop?

You can access it using:
$Week[1].mo

Related

Extract fields from Structure Array to put into another Structure Array

I have a structure array with a large number of fields that I don't care about, so I want to extract the limited number of fields I DO care about and put it into a separate structure array.
For a structure array of size one, I've done this by creating the new array from scratch, for example:
structOld.a = 1;
structOld.b = 2;
structOld.usefulA = 'useful information';
structOld.usefulB = 'more useful information';
structOld.c = 3;
structOld.d = 'words';
keepFields = {'usefulA','usefulB'};
structNew = struct;
for fn = keepFields
structNew.(fn{:}) = structOld.(fn{:});
end
which gives
structNew =
usefulA: 'useful information'
usefulB: 'more useful information'
Is there a more efficient way of doing this? How can I scale up to an structure array (vector) of size N?
N = 50;
structOld(1).a = 1;
structOld(1).b = 2;
structOld(1).usefulA = 500;
structOld(1).usefulB = 'us';
structOld(1).c = 3;
structOld(1).d = 'ef';
structOld(2).a = 4;
structOld(2).b = 5;
structOld(2).usefulA = 501;
structOld(2).usefulB = 'ul';
structOld(2).c = 6;
structOld(2).d = 'in';
structOld(3).a = 7;
structOld(3).b = '8';
structOld(3).usefulA = 504;
structOld(3).usefulB = 'fo';
structOld(3).c = 9;
structOld(3).d = 'rm';
structOld(N).a = 10;
structOld(N).b = 11;
structOld(N).usefulA = 506;
structOld(N).usefulB = 'at';
structOld(N).c = 12;
structOld(N).d = 'ion';
In this case, I'd like to end up with:
structNew =
1x50 struct array with fields:
usefulA
usefulB
Keeping elements with empty usefulA/usefulB fields is fine; I can get rid of them later if needed.
Using rmfield isn't great because the number of useless fields far outnumbers the useful fields.
You can create a new struct array using existing data as follows:
structNew = struct('usefulA',{structOld.usefulA},'usefulB',{structOld.usefulB});
If you have an arbitrary set of field names that you want to preserve, you could use a loop as follows. Here, I'm first extracting the data from strcutOld into a cell array data, which contains each of the arguments the the struct call in the previous line of code. data{:} is now a comma-separated list of these arguments, the last line of code below is identical to the line above.
keepFields = {'usefulA','usefulB'};
data = cell(2,numel(keepFields));
for ii=1:numel(keepFields)
data{1,ii} = keepFields{ii};
data{2,ii} = {structOld.(keepFields{ii})};
end
structNew = struct(data{:});

Powershell hashtable with multiple values and one key

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}

Random selection of a member's location in a nested cell of cells: Matlab

I have a nested cell of cells like the one below:
CellArray={1,1,1,{1,1,1,{1,1,{1,{1 1 1 1 1 1 1 1}, 1,1},1,1},1,1,1},1,1,1,{1,1,1,1}};
I need to randomly pick a location in CellArray. All members' locations of CellArray must have same chances to be chosen in the random selection process. Thanks.
You can capture the output of the celldisp function. Then use regex to extrcat indices:
s=evalc('celldisp(CellArray,'''')');
m = regexp(s, '\{[^\=]*\}', 'match');
Thanks to #excaza that suggested a clearer use of regexp
Result:
m =
{
[1,1] = {1}
[1,2] = {2}
[1,3] = {3}
[1,4] = {4}{1}
[1,5] = {4}{2}
[1,6] = {4}{3}
[1,7] = {4}{4}{1}
[1,8] = {4}{4}{2}
[1,9] = {4}{4}{3}{1}
[1,10] = {4}{4}{3}{2}{1}
[1,11] = {4}{4}{3}{2}{2}
[1,12] = {4}{4}{3}{2}{3}
[1,13] = {4}{4}{3}{2}{4}
[1,14] = {4}{4}{3}{2}{5}
[1,15] = {4}{4}{3}{2}{6}
[1,16] = {4}{4}{3}{2}{7}
[1,17] = {4}{4}{3}{2}{8}
[1,18] = {4}{4}{3}{3}
[1,19] = {4}{4}{3}{4}
[1,20] = {4}{4}{4}
[1,21] = {4}{4}{5}
[1,22] = {4}{5}
[1,23] = {4}{6}
[1,24] = {4}{7}
[1,25] = {5}
[1,26] = {6}
[1,27] = {7}
[1,28] = {8}{1}
[1,29] = {8}{2}
[1,30] = {8}{3}
[1,31] = {8}{4}
}
Use randi to select an index:
m{randi(numel(m))}

Masking fields duplications

I am trying to mask fields in a string as seen below. It is working to an extent, half way really. At some stage after the $addresspostcode the replacement characters aren't replacing for the correct positions. Would anyone have an idea of a fix?
The adressee0 line is from the output file
ADDRESSEE0|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY|YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY|ZZZZZZZZ|Sir or MadamZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ |A1|OM|Mr Patrick MurphyZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|45 CregtownZZZZZZZZZZZZZZZZ |EastRoad RoadZZZZZZZZZZZZZZZZ |TownnamersZZZZZZZZZZZZZZZZ |CityAB 16ZZZZZZZZZZZZZZZZ |ZZZZZZZZ| |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|ZZZZZZZZZZZZZZZZ |Sir or MadamZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ |IA|3319041| | |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZZZZZZZZ
ForEach-Object {
$addresseeName = $_.Substring(11,50)
$addresseeName2 = $_.Substring(62,50)
$addresseeLine1 = $_.Substring(113,30)
$addresseeLine2 = $_.Substring(144,30)
$addresseeLine3 = $_.Substring(175,30)
$addresseeLine4 = $_.Substring(206,30)
$addresseePostCode = $_.Substring(237,8)
$referenceAddressName1 = $_.Substring(303,50)
$referenceAddressName2 = $_.Substring(354,50)
$referenceAddresseeLine1 = $_.Substring(405,30)
$referenceAddresseeLine2 = $_.Substring(436,30)
$referenceAddresseeLine3 = $_.Substring(467,30)
$referenceAddresseeLine4 = $_.Substring(498,30)
$mask50 = 'X' * 50
$mask30 = 'Y' * 30
$mask08 = 'Z' * 8
# IF statement, if the string is at position 0-10, and begins with 'ADDRESSEE0'
# then run replace statement
if ($_.Substring(0,10) -eq 'ADDRESSEE0') {
$_.Replace($addresseeName, $mask50).Replace($addresseeName2, $mask50).Replace($addresseeLine1, $mask30).Replace($addresseeLine2, $mask30).Replace($addresseeLine3, $mask30).Replace($addresseeLine4, $mask30).Replace($addresseePostCode, $mask08).Replace($referenceAddressName1, $mask50).Replace($referenceAddressName2, $mask50).Replace($referenceAddresseeLine1, $mask30).Replace($referenceAddresseeLine2, $mask30).Replace($referenceAddresseeLine3, $mask30).Replace($referenceAddresseeLine4, $mask30)
The problem with your code is that it does the replace based on the contents of the string (rather than the position). This means if the same text exists elsewhere in the string, it replaces that text also, breaking the later replaces.
I suggest you do this instead:
$mask50 = 'X' * 50
$mask30 = 'Y' * 30
$mask08 = 'Z' * 8
$SomeInput | ForEach-Object {
if ($_.Substring(0,10) -eq 'ADDRESSEE0')
{
$SplitString = $_.Split('|')
1..2 | ForEach-Object { $SplitString[$_] = $mask50 }
3..6 | ForEach-Object { $SplitString[$_] = $mask30 }
$SplitString[7] = $mask08
8..9 | ForEach-Object { $SplitString[$_] = $mask50 }
10..13 | ForEach-Object { $SplitString[$_] = $mask30 }
$SplitString -Join '|'
}
}
This splits the string based on the | character and then does individual replaces for each (we use the .. array notation to make this a little more efficient).
Then we join the string again at the end with the | character.
Assuming ADDRESSEE0|... is the input string, why not split the data first? This provides manageable chunks instead of one giant string with truckload of method chaining. Like so,
# Get input data
$raw = `'ADDRESSEE0|ADDRESSEE1|ADDRESSEELine0|ADDRESSEELine1|...'`
# Split the string by each pipe | char. This uses regex syntax, so escape \ is needed
$lines = $raw -split '\|'
# Assign splitted elements into more readable variables
$addresseeName = $lines[0]
$addresseeName2 = $lines[1]
$addresseeLine1 = $lines[2]
...
# mask the data whatever way floats your boat
$addresseeName = $addresseeName.substring(0,9) + $mask08

Update table rows in Postgresql taking too much time

I am trying to update around 6000 rows in a table but my query never finishes.
I have put the data to be updated in a temp table and using a join to update rows.
This was working pretty fast in Sql Server but in Postgresql it never finishes.
I am updating around 40 columns.
Here is the sql I am running.
UPDATE "STG_magento_de".sales_flat_order
SET customer_id = b.customer_id
,created_at = b.created_at
,updated_at = b.updated_at
,coupon_code = b.coupon_code
,box_id = b.box_id
,beautytrends_glossydots = b.beautytrends_glossydots
,billing_address_id = b.billing_address_id
,shipping_address_id = b.shipping_address_id
,base_discount_amount = b.base_discount_amount
,base_discount_canceled = b.base_discount_canceled
,base_discount_invoiced = b.base_discount_invoiced
,base_discount_refunded = b.base_discount_refunded
,base_grand_total = b.base_grand_total
,base_shipping_amount = b.base_shipping_amount
,base_shipping_canceled = b.base_shipping_canceled
,base_shipping_invoiced = b.base_shipping_invoiced
,base_shipping_refunded = b.base_shipping_refunded
,base_shipping_tax_amount = b.base_shipping_tax_amount
,base_shipping_tax_refunded = b.base_shipping_tax_refunded
,base_subtotal = b.base_subtotal
,base_subtotal_canceled = b.base_subtotal_canceled
,base_subtotal_invoiced = b.base_subtotal_invoiced
,base_tax_amount = b.base_tax_amount
,base_tax_canceled = b.base_tax_canceled
,base_tax_invoiced = b.base_tax_invoiced
,base_tax_refunded = b.base_tax_refunded
,base_to_global_rate = b.base_to_global_rate
,base_to_order_rate = b.base_to_order_rate
,base_total_canceled = b.base_total_canceled
,base_total_invoiced = b.base_total_invoiced
,base_total_invoiced_cost = b.base_total_invoiced_cost
,base_total_offline_refunded = b.base_total_offline_refunded
,base_total_online_refunded = b.base_total_online_refunded
,base_total_paid = b.base_total_paid
,base_total_qty_ordered = b.base_total_qty_ordered
,base_total_refunded = b.base_total_refunded
,increment_id = b.increment_id
,order_type = b.order_type
,STATUS = b.STATUS
,is_chargerun = b.is_chargerun
,chargeback_flag = b.chargeback_flag
,gift_message_id = b.gift_message_id
,dispatch = b.dispatch
FROM "STG_magento_de".sales_flat_order a
JOIN "STG_magento_de".sales_flat_order_temp b ON a.entity_id = b.entity_id
From the manual:
Note that the target table must not appear in the from_list, unless you intend a self-join (in which case it must appear with an alias in the from_list).
(emphasis mine)
So you actually want:
UPDATE "STG_magento_de".sales_flat_order
SET customer_id = b.customer_id,
....
from sales_flat_order_temp b --<< do NOT repeat the target table here
where "STG_magento_de".sales_flat_order = b.entity_id`
Unrelated, but: you should really avoid those dreaded quoted identifiers. They are much more trouble than they are worth.