Hello if i have 2 text files like this
file1
jack : 10
donald : 50
mark : 20
florence : 15
ariel : 50
arnold : 50
file2
jack
country : ohaio
donald
country : italy
mark
country : france
florence
country : china
ariel
country :america
arnold
country: japan
how can i to get country names of people older than 20 looping through ages in file1 to get names of people first then after i get names loop through them in file2 to get countries.// don't know how to deal with duplicate ages,this is just sample files there is a lot more values than that.
so output should be something like this:
ages
10
20
50
15
50
50
values over 20
50
50
50
names
donald
ariel
arnold
countries
italy
america
japan
the following code presumes the entries in the two files are in the EXACT same sequence ... and they have EXACTLY the same number of entries. [grin]
what it does ...
sets the name & location of the input files
creates the files to work with
comment out or remove this region when ready to work with real data.
reads in the 1st file as an array of single lines
reads in the 2nd file as an array of 3-line chunks
iterates thru the two collections in parallel using the index number of the 1st collection
the .GetUpperBound(0) gets the upper limit of the zero axis of the collection.
builds a PSCustomObject of the desired items
it uses the $Index to decide what to work on.
the [1] after the Country file index grabs the 2nd line of the 3-line chunk.
sends the PSCO out to the $Results collection
displays it on screen
filters the collection for the items where the .Age property is over 20
the code ...
$File_1_Name = "$env:TEMP\3N16M4_File1.txt"
$File_2_Name = "$env:TEMP\3N16M4_File2.txt"
#region >>> create files to work with
$NameAge = #'
jack : 10
donald : 50
mark : 20
florence : 15
ariel : 50
arnold : 50
'# | Set-Content -LiteralPath $File_1_Name -ErrorAction 'SilentlyContinue'
$NameCountry = #'
jack
country : ohaio
donald
country : italy
mark
country : france
florence
country : china
ariel
country :america
arnold
country: japan
'# | Set-Content -LiteralPath $File_2_Name -ErrorAction 'SilentlyContinue'
#endregion >>> create files to work with
$NameAge = Get-Content -LiteralPath $File_1_Name
# the "-ReadCount" parameter grabs lines in groups
$NameCountry = Get-Content -LiteralPath $File_2_Name -ReadCount 3
# this code presumes the two files are in the EXACT same sequence
# and that they have EXACTLY the same number of entries
$Results = foreach ($Index in 0..$NameAge.GetUpperBound(0))
{
[PSCustomObject]#{
Name = $NameAge[$Index].Split(':')[0].Trim()
Age = $NameAge[$Index].Split(':')[-1].Trim()
Country = ($NameCountry[$Index][1] -replace '(?ms).+:', '').Trim()
}
}
# show whole collection on screen
$Results
'=' * 30
# show the filtered results
$Results.Where({$_.Age -gt 20})
on screen display - the whole collection is above the line, the filtered items are below it ...
Name Age Country
---- --- -------
jack 10 ohaio
donald 50 italy
mark 20 france
florence 15 china
ariel 50 america
arnold 50 japan
==============================
donald 50 italy
ariel 50 america
arnold 50 japan
Related
Related to PowerShell 5.1
I was playing around with XML to show how to handle conflicting namespaces. Here's the example I created:
<Employees>
<ms:Employee id='1' xmlns:ms="MicrosoftEmployees">
<FirstName>Bill</FirstName>
<LastName>Gates</LastName>
</ms:Employee>
<ms:Employee id='2' xmlns:ms="MicrosoftEmployees">
<FirstName>Paul</FirstName>
<LastName>Allen</LastName>
</ms:Employee>
<ap:Employee id='1' xmlns:ap="AppleEmployees">
<Name>Steve Jobs</Name>
</ap:Employee>
<ap:Employee id='2' xmlns:ap="AppleEmployees">
<Name>Steve Wozniak </Name>
</ap:Employee>
</Employees>
The scenario might be combining data from two different companies.
PowerShell demonstration program:
cls
$filename = "c:\XMLClass\IntroSamples\Sample05_Simpler_Namespace.xml"
[xml]$xmlDoc = Get-Content $filename
$xmlDoc.Employees.Employee[0]
$xmlDoc.Employees.Employee[1]
$xmlDoc.Employees.Employee[2]
$xmlDoc.Employees.Employee[3]
Output:
id ms FirstName LastName
-- -- --------- --------
1 MicrosoftEmployees Bill Gates
2 MicrosoftEmployees Paul Allen
1
2
Is there anyway to get a more logical output?
It seems like PowerShell locks into the first schema it sees for the Employee element, then cannot show the Name element of the Apple employees. This actually makes sense, but I was just checking to see if there is something fancier to handle this that I might be missing.
I know I could use SelectSingleNodes and XPath, but was just trying to see if and how PowerShell could handle this "out of the box".
If I reverse the code:
$xmlDoc.Employees.Employee[2]
$xmlDoc.Employees.Employee[3]
$xmlDoc.Employees.Employee[1]
$xmlDoc.Employees.Employee[0]
Then the output is:
id ap Name
-- -- ----
1 AppleEmployees Steve Jobs
2 AppleEmployees Steve Wozniak
1 ms:Employee
2 ms:Employee
Use format list to see all the properties. Format-table doesn't handle different sets of properties well.
$xmldoc.employees.employee | format-list
id : 1
ms : MicrosoftEmployees
FirstName : Bill
LastName : Gates
id : 2
ms : MicrosoftEmployees
FirstName : Paul
LastName : Allen
id : 1
ap : AppleEmployees
Name : Steve Jobs
id : 2
ap : AppleEmployees
Name : Steve Wozniak
I have an System.Array object called $Data, the first ([0]) item looks like this:
RecordDate : {43739, 43740, 43741, 43742...}
MAX_LAST_UPDATE_DATE : 30/10/2019 14:08:33
EMPLOYEE_NUMBER : 1000522
EFFECTIVE_START_DATE : 01/10/2019 00:00:00
EFFECTIVE_END_DATE : 31/12/4712 00:00:00
CC : 0726
REGION_NAME : Head Office
LOCATION_NAME : Inventory
FIRST_NAME : Name
MIDDLE_NAMES : Mid
LAST_NAME : Last
KNOWN_AS : NickName
JOB_TITLE : Inventory Manager
WORK_NUMBER :
Employment Category : Full Time
NORMAL_HOURS : 40
GROUP_NAME : Indirect
Manager Employee Number : 1034422
PERSON_TYPE : Employee
HIRE_DATE : 16/11/1983 00:00:00
TERMINATION_DATE :
DATE_OF_BIRTH : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER : 111
I'm trying to kind of unpivot the first column "RecordDate" on the entire array like this:
RecordDate : 43739
MAX_LAST_UPDATE_DATE : 30/10/2019 14:08:33
EMPLOYEE_NUMBER : 1000522
EFFECTIVE_START_DATE : 01/10/2019 00:00:00
EFFECTIVE_END_DATE : 31/12/4712 00:00:00
CC : 0726
REGION_NAME : Head Office
LOCATION_NAME : Inventory
FIRST_NAME : Name
MIDDLE_NAMES : Mid
LAST_NAME : Last
KNOWN_AS : NickName
JOB_TITLE : Inventory Manager
WORK_NUMBER :
Employment Category : Full Time
NORMAL_HOURS : 40
GROUP_NAME : Indirect
Manager Employee Number : 1034422
PERSON_TYPE : Employee
HIRE_DATE : 16/11/1983 00:00:00
TERMINATION_DATE :
DATE_OF_BIRTH : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER : 111
RecordDate : 43740
MAX_LAST_UPDATE_DATE : 30/10/2019 14:08:33
EMPLOYEE_NUMBER : 1000522
EFFECTIVE_START_DATE : 01/10/2019 00:00:00
EFFECTIVE_END_DATE : 31/12/4712 00:00:00
CC : 0726
REGION_NAME : Head Office
LOCATION_NAME : Inventory
FIRST_NAME : Name
MIDDLE_NAMES : Mid
LAST_NAME : Last
KNOWN_AS : NickName
JOB_TITLE : Inventory Manager
WORK_NUMBER :
Employment Category : Full Time
NORMAL_HOURS : 40
GROUP_NAME : Indirect
Manager Employee Number : 1034422
PERSON_TYPE : Employee
HIRE_DATE : 16/11/1983 00:00:00
TERMINATION_DATE :
DATE_OF_BIRTH : 23/05/1966 00:00:00
NATIONAL_IDENTIFIER : 111
RecordDate : 43741
MAX_LAST_UPDATE_DATE : 30/10/2019 14:08:33
...
Is there a way to do that with some sneaky Select -expandproperty or do the opposite of what Group-Object is capable of; without doing combination of for($i) and for($j) loops?
It's quite simple on a Table in in Excel PowerQuery, as you just click Expand and voilĂ .
Regards, Jarek
You can combine Select-Object -ExpandProperty with the common -PipelineVariable parameter and cloning (PSv3+ syntax):
For input collections of [pscustomobject] or [hashtable] instances:
# Sample input array of custom objects to expand by .RecordDate
$array =
[pscustomobject] #{ RecordDate = 1, 2; OtherProp1 = 'one'; OtherProp2 = 'two' },
[pscustomobject] #{ RecordDate = 3, 4; OtherProp1 = 'three'; OtherProp2 = 'four' }
# Write the array elements to the pipeline, and store each in variable
# $objectOrHashtable for use in a later pipeline segment.
Write-Output $array -PipelineVariable objectOrHashtable |
# Expand the input object's .RecordData property, i.e. send its
# elements one by one to the next pipeline segment.
Select-Object -ExpandProperty RecordDate |
ForEach-Object {
# Clone the original input object.
$clone = if ($objectOrHashtable -is [Management.Automation.PSCustomObject]) {
$objectOrHashtable.psobject.Copy()
} else { # assume [hashtable] or a type that implements [System.ICloneable]
$objectOrHashtable.Clone()
}
# Assign the record date at hand to the clone...
$clone.RecordDate = $_
# ... and output it.
$clone
}
The above yields the following; note that 4 objects were output, based on enumerating the elements of the input objects' .RecordDate array while retaining all other properties:
RecordDate OtherProp1 OtherProp2
---------- ---------- ----------
1 one two
2 one two
3 three four
4 three four
Note:
The above works with two types of input object:
custom objects ([pscustomobject] instances, such as created by Import-Csv)
Note: For technical reasons you cannot use -is [pscustomobject] and must instead use the full type name, System.Management.Automation.PSCustomObject (the System. prefix can be omitted); [pscustomobject], for historical reasons, is the same as [psobject] (System.Management.Automation.PSObject), and -is [psobject] is also true for objects that aren't custom objects.
hashtables (System.Collections.Hashtable instances - but not [ordered] hashtables); more generally, any type that implements System.ICloneable.
The cloning that is performed on custom objects and hashtable is shallow (member-wise), but with scalar string and numeric values that is sufficient.
Generally, the ICloneable interface doesn't prescribe the specifics of the cloning behavior, which is why its use is generally discouraged.
For input collections of [System.Data.DataRow] instances:
Cloning a collection of System.Data.DataRow instances - the rows of data table, System.Data.DataTable - requires custom cloning logic, but the approach and structure of the output are fundamentally the same:
# Create a sample DataTable...
$dt = [System.Data.DataTable]::new('sample')
# ... define the columns ...
$dt.Columns.AddRange([System.Data.DataColumn[]] (
#{ ColumnName = 'RecordDate'; DataType = [object[]] },
#{ ColumnName = 'OtherProp1'; DataType = [string] },
#{ ColumnName = 'OtherProp2'; DataType = [string] }
))
# ...and add sample rows.
#{ RecordDate = 1, 2; OtherProp1 = 'one'; OtherProp2 = 'two' },
#{ RecordDate = 3, 4; OtherProp1 = 'three'; OtherProp2 = 'four' } | % {
$dt.Rows.Add(($dr = $dt.NewRow()))
foreach ($entry in $_.GetEnumerator()) {
$dr[$entry.Key] = $entry.Value
}
}
# Create an auxiliary, empty clone of the input data table
# to facilitate cloning of individual rows.
$dtAux = $dt.Clone()
# Write the data rows to the pipeline, and store each in variable
# $obj for use in a later pipeline segment.
Write-Output $dt.Rows -PipelineVariable row |
# Expand the input object's .RecordData property, i.e. send its
# elements one by one to the next pipeline segment.
Select-Object -ExpandProperty RecordDate |
ForEach-Object {
# Clone the data row at hand.
$dtAux.Clear(); $dtAux.ImportRow($row)
$clone = $dtAux.Rows[0]
# Assign the record date at hand to the clone...
$clone.RecordDate = #($_)
# ... and output it.
$clone
}
I have two tables where I want to join them and do a look up from one to find the column heading in another.
One table looks like this:
table: student_score
student| red |blue |green
------- -------- ------- -----
201 | 88 |89 |78
345 | 67 |72 |95
987 | 75 |81 |89
The other is like this:
table: student_history
student | color_last_year
------- -----------------
201 | red
345 | blue
987 | green
I'm looking to create a query in PostgreSQL that will allow me to pick last year's color (from the history table) as the column heading from the score table. In the past I've used javascript to do this, but would prefer to do it all in one psql query.
The js looked something like this:
function lastYear(color){
var query = 'SELECT student_score.' + color + '
FROM student_score
JOIN student_score ON student_score.student =
student_history.student
//...more code .... //;'
}
I've been trying to find help around this in documentation and searches, but not sure how best to set up my query.
You can use a case expression:
select
s.student,
case h.color_last_year
when 'red' then s.red
when 'blue' then s.blue
when 'green' then s.green
end as val
from student_score s
join student_history h on s.student = h.student;
I'm working on a report that contains inpatient ("IP") surgical visits and the service dates of the follow-up x-ray visits, which is based on patient type and revenue code:
MRN AdmitDate Pattype RevCode ServiceDate
123 1/1/2015 IP 100 *null*
123 *null* PT 200 2/1/2015
123 *null* SVO 320 2/10/2015
123 *null* PT 200 2/15/2015
I'm trying to roll up rows 1 and 3 on a single line to appear as follows:
MRN AdmitDate Pattype FollowUp
123 1/1/2015 IP 2/10/2015
but am getting either an empty return or just the next record in the dataset using #followup =
If {encounter.pattype} = "IP" then
if next ({encounter.pattype}) in [several different patient types]
if {charge_detail.revenuecode} in ["0320" to "0324"] then
{charge_detail.servicedate}
I have a strange issue. I have a report CR. In the Selection Formula I do a test on two fields. The test is simple like that : {field_City} = 'Paris' OR {field_Country} = 'France'.
This is a sample of the data in my table:
|---------------|---------------|---------------|
| ID_Record | Country | City |
|---------------|---------------|---------------|
| 1 | null | Paris |
|---------------|---------------|---------------|
| 2 | France | null |
|---------------|---------------|---------------|
| 3 | France | Paris |
|---------------|---------------|---------------|
The result of the Selection should be the 3 records, however it's excluding the 2 first rows where there is a null value in one of the columns. Then I changed the Selection Formula like this to consider null values too : ({field_City} = 'Paris' AND (isnull({field_Country}) OR not(isnull({field_Country})))) OR ({field_Country} = 'France' AND (isnull({field_City}) OR not(isnull({field_City})))) but I am still getting only the last record ! To ensure myself that my code is correct, I generated the sql query via the option in CR 'Show sql query', then i've added a WHERE clause in which I wrote the same condition that i've put in the Selection Formula, and...... it gave me the 3 records ! Unfortunately I can't work with the sql query, I have to find out why the formula is excluding the records that have a null value in one of the columns :( I hope that you can help me. Thanks a lot !
This is the solution: ((isnull({field_Country}) AND {field_City} = 'Paris') OR (isnull({field_City}) AND {field_Country} = 'France') OR (not(isnull({field_Country})) AND {field_City} = 'Paris') OR (not(isnull({field_City})) AND {field_Country} = 'France')) , Thank you so much Craig!
You need to test for null values first:
( Not(Isnull({field_Country})) AND {field_Country}='France' )
OR
( Isnull({field_Country}) AND {field_City}='Paris' )