2

I'm having a little trouble finding the index of a hashtable in an array. I create a JSON with this code:

$start = {
Clear-Host
$BIB = Read-Host 'Bibliothek'
$BIBName = Read-Host 'Bibliothek Name'
$Standort = Read-Host 'Bibliothek Standort'
$Autor = Read-Host 'Buchautor'
$BuchName = Read-Host 'Buchname'

$jsonfile = "C:\Skripte\bibV2-1000.xml"
if(![System.IO.File]::Exists($jsonfile)){
    $Data = @{BIBs = @(
        @{$BIB = @{BIBName=$BIBName}, 
        @{Standort = $Standort}, 
        @{Bücher = @(
            @{BuchName = $BuchName; 
            Autor = $Autor})
        }}
    )}
    ConvertTo-Json -Depth 50 -InputObject $Data | Add-Content $jsonfile
    .$continue
} else {
        $jsonfile = "C:\Skripte\bibV2-1000.json"
        $Data = Get-Content $jsonfile | ConvertFrom-Json
        $Data.BIBs += New-Object -TypeName psobject -Property @{$BIB = 
               @{BIBname=$BIBName},
               @{Standort=$Standort},
               @{Bücher = @(@{
                    Buchname=$BuchName;
                    Autor=$Autor})
               }
        }
        ConvertTo-Json -Depth 50 -InputObject $Data | Out-File $jsonfile}
        .$continue
}


$continue = {
Write-Host ""
Write-Host "Was wollen Sie machen?"
Write-Host "(1) Eine weitere Bibliothek hinzufügen"
Write-Host "(2) Einer Bibliothek neue Bücher hinzufügen"
Write-Host "(E) Script beenden"

    If (($read = Read-Host ) -eq "1") {
    &$start} else {
            if (($read) -eq "2") {
                . C:\Skripte\büc.ps1 } else {
                    if (($read) -eq "E") {
                        exit} else {
                            Write-Host "+++ FALSCHE EINGABE! Bitte wählen Sie (1) oder (2) für die entsprechende Aktion +++"
                            .$continue
                        }
                }
    }
}
&$start

The output is as follows:

{
    "BIBs": [{
        "BIB1": [{
            "BIBName": "123"
        },
            {
                "Standort": "123"
            },
            {
                "Bücher": [{
                    "Autor": "123",
                    "BuchName": "123"
                }]
            }
        ]
    },
        {
            "BIB2": [{
                "BIBname": "345"
            },
                {
                    "Standort": "345"
                },
                {
                    "Bücher": [{
                        "Autor": "345",
                        "Buchname": "345"
                    }]
                }
            ]
        }
    ]
}

Now I want to find out the index of "BIB1". I already tried the IndexOf()-Method which should create the output "0" but it gives me "-1" instead, because it can't find the value. How can I get the index of "BIB1"?

EDybck
  • 43
  • 1
  • 7
  • 1
    can you show the objects you are working with? this just looks like a json object – Eli Skoran Mar 20 '18 at 11:46
  • Please edit your question with this information. Reading code in comments sucks... – EBGreen Mar 20 '18 at 12:15
  • 1
    So. One thing about ConvertTo-Json is that it doesn't make a "Json Object". It just creates a Json formatted string. If you want a structured data object that you can easily manipulate and poke around in I would suggest either leaving it as a hash of arrays and hashes as you had it before you converted it or converting it to XML. – EBGreen Mar 20 '18 at 12:23
  • I already tried it without converting it to json, but the output of IndexOf() is still "-1" – EDybck Mar 20 '18 at 12:42
  • Already tried what? Already tried how? What code did you try with? – EBGreen Mar 20 '18 at 12:43
  • The code that you have provided will not run since you did not provide all the code. Please create a [Minimal, complete, and verifiable](https://stackoverflow.com/help/mcve) example of your situation. – EBGreen Mar 20 '18 at 12:46
  • I filled $Data with values but didn't convert it to json. After that I tried `$Data.BIBs.IndexOf('BIB1') to get the index of the first value "BIB1". The output was still "-1" instead of "0", it somehow can't find the value "BIB1". – EDybck Mar 20 '18 at 12:48
  • $Data.BIBs is an array of ***HashTables*** you are asking it to tell you the location of a ***String***. That string literally does not exist as a member of that array. It is a key in a hashtable that is a member of that array. – EBGreen Mar 20 '18 at 12:55
  • That's the problem, how can I adress the hashtable to get its index in the array of $Data.BIBs? – EDybck Mar 20 '18 at 12:57
  • Let's back up a little. Why are you using this data structure? Are you locked into doing it this way because you are required to produce that specific Json? – EBGreen Mar 20 '18 at 13:48
  • Exactly, I can't alter the structure as it is needed this way. The structure is going to be used for an onboarding-process for customers in a project that I'm working on. The idea behind my question is, that I want to add another value to e.g. **"BIB1"** or even **"Bücher"**. Therefor I already coded a snippet for adding a value to it. But the code is only functioning with the index of the array. So I want to find out the index of "BIB1" dynamically instead of hardcoding it, because hardcoding the index is not a proper way of doing that task. `$Data.BIBs[0].BIB1[2].Bücher += @{A="B";C="F"}` – EDybck Mar 20 '18 at 13:57
  • Well, I would say that if you are working on the project maybe you should work on a less complicated data structure. Without that as an option though, give me a minute to mock up an actual [MCVE](https://stackoverflow.com/help/mcve) that I can use. – EBGreen Mar 20 '18 at 14:03

2 Answers2

2

Judging by your earlier question, you're attempting to get the index of a specific object so you can access it via its containing array. However, you can do this more directly: $objOfInterest = $Data.BIBs | ? BIB1 - see my answer to your earlier question for details.

You need to iterate over the array elements of $Data.BIBs, which - on reading your serialized-to-a-file-as-JSON hashtables back in with ConvertFrom-Json - are custom objects (as Ansgar correctly points out; they are instances of [System.Management.Automation.PSCustomObject]), and check each for the presence of property 'BIB1':

  • (In a hashtable, you'd check for the presence of key 'BIB1' with .ContainsKey('BIB1'))

  • To test the existence of an object property, you need reflection, which is most easily - but somewhat obscurely - achieved via the hidden .PSObject property, as demonstrated in Ansgar Wiechers' more elegant solution.

However, given that the properties of interest have nonempty values, we can infer from the presence of a nonempty value that a given property exists, using implicit Boolean (logic): $obj.'BIB1' by default returns $null if there is no BIB1 property, which is "falsy" in a Boolean context such as an if conditional; conversely, any nonempty value is "truthy":

$propName = 'BIB1'
$i = $ndx = -1
foreach ($obj in $Data.BIBs) {
  ++$i
  if ($obj.$propName) { $ndx = $i; break}
}
$ndx  # $ndx now contains the index of the target object or -1 if there was no match
mklement0
  • 382,024
  • 64
  • 607
  • 775
2

$Date.BIBs is an array of custom objects, not hashtables (since you wrote your original data to a JSON file and then converted that back), so you need something like this:

$arr = $Data.BIBs | ForEach-Object { $_.PSObject.Properties.Name }
$arr.IndexOf('BIB1')  # returns 0
$arr.IndexOf('BIB2')  # returns 1
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328