I have an array of strings in Powershell. For each element I want to concatenate a constant string with the element and update the array at the corresponding index. The file I am importing is a list of non-whitespace string elements separated by line breaks.
The concatenation updating the array elements does not seem to take place.
$Constant = "somestring"
[String[]]$Strings = Get-Content ".\strings.txt"
foreach ($Element in $Strings) {
$Element = "$Element$Constant"
}
$Strings
leads to the following output:
Element
Element
...
Following the hint of arrays being immutable in Powershell I tried creating a new array with the concatenated values. Same result.
What do I miss here?
you concatenate the values to the local variable $Element but this does not change the variable $Strings
here is my approach, saving the new values to $ConcateStrings. by returning the concatenated string and not assigning it to a local variable the variable $ConcateStrings will have all the new values
$Constant = "somestring"
$Strings = Get-Content ".\strings.txt"
$ConcateStrings = foreach ($Element in $Strings) {
"$Element$Constant"
}
$ConcateStrings
Just to show an alternative iterating the indices of the array
$Constant = "somestring"
$Strings = Get-Content ".\strings.txt"
for($i=0;$i -lt $Strings.count;$i++) {
$Strings[$i] += $Constant
}
$Strings
Sample output with '.\strings.txt' containing one,two,three
onesomestring
twosomestring
threesomestring
Related
I use an array reading Excel content which should be used to create an xml file, but have troubles to allocate the array values to the write xml statements.
Code of the array:
# Parse Excel columns A and B and store it in array "$headerInit"
for ($j=1; $j -le $rowMax-1; $j++)
{
$Obj = New-Object Psobject -Property #{
Value = $ws.Cells.Item($j,2).text
Header = $ws.Cells.Item($j,1).text
No = $j
}
$DataArray.add($obj) # Visualize the array content
}
$DataArray | Out-Gridview
Example of the array content:
No Header Value
...
12 Address 1234,0x3030
...
Here the code excerpt to create the xml document (values "1234" and "0x3030" are insert manually, but should be allocated from the array $DataArray):
...
# Write node <address1>
$xmlWriter.WriteStartElement('address1')
$xmlWriter.WriteAttributeString('address','1234')
$xmlWriter.WriteEndElement() # <-- Closing the node <address1>
# Write node <address2>
$xmlWriter.WriteStartElement('address2')
$xmlWriter.WriteAttributeString('address','0x3030')
$xmlWriter.WriteEndElement() # <-- Closing the node <address2>
...
How can I allocate the 2 values, divided by comma "1234,0x3030" from the array $DataArray, Header "Address" in the create xml statement? Any help is appreciated - Thanks.
Meanwhile I have solved the issue seperating the 2 values devided by comma.
Solution is:
$a,$b = $DataArray[12].Value.split(',')
Is there any easy way to alocate the values direct to the write xml statement without additional variables?
As you've found from my suggestion, you can use Split to separate the two values you want:
$addressLeft,$addressRight = $DataArray[12].Value.Split(',')
You can also reference the seperate parts of the split directly, as Split creates an array you can use the index number to access each element:
$DataArray[12].Value.split(',')[0]
$DataArray[12].Value.split(',')[1]
The other option is to split the value into two propertys when you build $DataArray:
$Obj = New-Object Psobject -Property #{
Value = $ws.Cells.Item($j,2).text
addressLeft = $ws.Cells.Item($j,2).text.Split(',')[0]
addressRight = $ws.Cells.Item($j,2).text.Split(',')[1]
Header = $ws.Cells.Item($j,1).text
No = $j
}
I've left the original Value property in, but you could remove it if you only want the split values.
I'm working in powershell with an imported CSV. I have a data set like this:
ID First_Name Last_Nam
-- ---------- --------
2314 Kenny Anderson
21588 Mark Anderson
2547 Ben Andrews
5797 Benjamin Armour
Except with 2000 people and many more columns. Currently the data is stored as a series of hashes in a #{ID = "..",First_Name:"..",Last_Name:".."} and these are stored in a System Object array. I want to store each hash as an index in an array. I want to get the hashtable at that index, but I don't know how to into the System.Object Array. Here's my code:
$csv = import-csv $csv_name
$row = #(0)*csv.length
$hash = #{}
for($i =0; $i -lt $csv.length; $i++){
$row[$i] += $csv[$i]
}
#error: cannot convert "#{ID : "..", First_Name: "..", Last_Name:".." to Systems.Int32
for($i =0; $i -lt $csv.length; $i++){
$csv[$i].psobject.properties | Foreach { $hash[$_.Name] = $_.Value }
$row[$i]+=$hash
}
#error: Cannot convert systems.collections.hashtable into Systems.Int32
I'm looking for a way to index the array so I can get the hashtable at that index. the The first one, with pointers to the hashtables accessible through the array, is what I think would be the easiest to manipulate. If there's an easier way to get a specific hashtable just from the System.Object[] itself, please tell me.
I should add I don't know the names or amount of the columns in advance.
The return value of Import-Csv is not an array of [hashtable]s, it's an array of [psobject]s, where each column is a property.
There's no need to build any kind of array to get an individual object by index.
$csv = import-csv $csv_name
$csv[0]
$csv[1].First_Name
# etc
The errors in your code have nothing to do with the question you posed though; you're getting errors trying to add objects to an array, because you're actually trying to add an object or hashtable to an existing array element of type integer.
You don't need to precreate the array with a bunch of zeros, so this line isn't needed:
$row = #(0)*csv.length
Instead, you can create an empty array:
$row = #()
Then, you can just add to the array itself:
$row += $hash
Suppose I have an array with random values in it, like for instance
$a=#(0..5)
and I would like to format that array in a string like this :
{0,1,2,3,4}
comma separated values between curly braces. The "catch" is that I don't know in advance the size of the array, and in some cases, when there's only one record the type won't be array but psobject, when it's a unique PSObject I don't need curly braces and commas, I want to leave it as it is.
Thanks!
I would go for this (if statement on the input object type, and use of #beatcracker's method) :
Code :
//insert an array and a custom object in an input array
$input = #(#(0, 1, 2, 3, 4, 5),
[PSCustomObject]#{ title = "My"; first = "Custom"; last = "Object" })
//an empty output array
$output = #()
//foreach item in the input array
foreach($item in $input) {
//if item base type is array
if($item.GetType().BaseType.Name -eq "Array") {
//process and add to output array
$output += "{{{0}}}" -f ($item -join ",")
} else {
//add to output array as-is
$output += $item
}
}
//echo output array
$output
Output :
{0,1,2,3,4,5}
title first last
----- ----- ----
My Custom Object
Info : {0} is a placeholder for the 1st value after -f, ($item -join ",") ; the next one would have been {1} (more info here).
Additional curly brackets are there to escape surrounding curly brackets to make sure they appear in the final string.
I am trying to print out a concatenated string in Perl, but I'm getting a weird result. Here is a bit of my code, I am getting a string and taking out a part of it and putting it into an array, #array. I'm then trying to take pieces of that array and concatenate them into a string.
#input = [];
while ( $in = <STDIN> ) {
print "# got $in";
chomp $in;
#inS = split(/ /, $in);
if ($inS[2] ne ".pau"){
print "$inS[2]";
push(#input, $inS[2]);
}
}
$inputSize = #input;
$stringN = "";
for ($i = 0; $i < $inputSize; $i++) {
$stringN .= $input[$i];
print "$stringN\n";
}
But the result I get from printing gets this big number attached onto the front. Here is an example. Instead of getting just "faIv", I get:
ARRAY(0x500f450)faIv
It seems like it thinks my string is an array? Is that because of concatenating with an array element? Any assistance would be very helpful, thank you.
[] is a reference to an array. #input = []; creates an array named #input and puts a reference to an empty array as the first element of #input. If you want to initialize #input to an empty array, use #input = ();.
After reading this helpful article on the Windows PowerShell Blog, I realized I could "shift" off the first part of an array, but didn't know how to "unshift" or push elements onto the front of an array in PowerShell.
I am creating an array of hash objects, with the last read item pushed onto the array first. I'm wondering if there is a better way to accomplish this.
## Create a list of files for this collection, pushing item on top of all other items
if ($csvfiles[$collname]) {
$csvfiles[$collname] = #{ repdate = $date; fileobj = $csv }, $csvfiles[$collname] | %{$_}
}
else {
$csvfiles[$collname] = #{ repdate = $date; fileobj = $csv }
}
A couple of things to note:
I need to unroll the previous array element with a foreach loop %{$_}, because merely referencing the array would create a nested array structure. I have to have all the elements at the same level.
I need to differentiate between an empty array and one that contains elements. If I attempt to unroll an empty array, it places a $null element at the end of the array.
Thoughts?
PS: The reason the empty hash element produces a NULL value is that $null is treated as a scalar in PowerShell. For details, see https://connect.microsoft.com/PowerShell/feedback/details/281908/foreach-should-not-execute-the-loop-body-for-a-scalar-value-of-null.
ANSWER:
Looks like the best solution is to pre-create the empty array when necessary, rather than code around the $null issue. Here's the rewrite using a .NET ArrayList and a native PoSh array.
if (!$csvfiles.ContainsKey($collname)) {
$csvfiles[$collname] = [System.Collections.ArrayList]#()
}
$csvfiles[$collname].insert(0, #{ repdate = $repdate; fileobj = $csv })
## NATIVE POSH SOLUTION...
if (!$csvfiles.ContainsKey($collname)) {
$csvfiles[$collname] = #()
}
$csvfiles[$collname] = #{ repdate = $repdate; fileobj = $csv }, `
$csvfiles[$collname] | %{$_}
You might want to use ArrayList objects instead, as they support insertions at arbitrary locations. For example:
# C:\> $a = [System.Collections.ArrayList]#(1,2,3,4)
# C:\> $a.insert(0,6)
# C:\> $a
6
1
2
3
4
You can simply use a plus operator:
$array = #('bar', 'baz')
$array = #('foo') + $array
Note: this re-creates actually creates a new array instead of changing the existing one (but the $head, $tail = $array way of shifting you refer to works extactly in the same way).