Find first available serial based on list of strings?

后端 未结 4 1111
挽巷
挽巷 2021-01-26 02:34

Given a list of strings such as: apple01, apple02, and apple04, banana02, cherry01, how would you come up with t

相关标签:
4条回答
  • 2021-01-26 02:44

    This could be the start of what you are looking for. I took a very similar approach as PetSerAl has done in his comment. I have made mine more verbose as it helps to take in what is happening here. Most of the explanation comes from comments in the code.

    # Array of fruits/index values. Using string array as proof on concept.
    $fruits = "apple01","apple02","apple04","banana02","cherry01"
    
    # Regex -match the fruit name and index number. This also filters out lines that do not match the standard.
    $fruityArray = $fruits | Where-Object{$_ -match '^(.+?)(\d+)$' } | ForEach-Object{
        # Create a simple object that splits up the matched info into a fruit index object
        [pscustomobject][ordered]@{
            Fruit = $matches[1]
            Index = [int]$matches[2]
        }
    }
    
    # Group by fruit and then we can find the next available index within the groups
    $fruityArray | Group-Object Fruit | ForEach-Object{
        # For this fruit determine the next available index
        $thisFruitGroup = $_
    
        # Determine the highest index value. We add one in case all indexes are present from 1 to highest
        $highestPossibleIndex = ($thisFruitGroup.Group.Index | Measure-Object -Maximum).Maximum + 1
    
        # Check all possible indexes. Locating all that are free but filter the first one out
        $nextAvailableIndex = 1..$highestPossibleIndex | Where-Object{$_ -notin $thisFruitGroup.Group.Index} | Select -First 1
    
        # Take the fruit and add a padded index then pass that value to the pipeline. 
        '{0}{1:00}'-f $thisFruitGroup.Name, $nextAvailableIndex
    }
    

    We take the array of fruits and create an object array of fruit and indexes. Group those together by fruit and then determine the next available index based on all available indexes for that fruit. We add one to the highest possible index on the chance that they are all in use (no gaps). This is the case for cherry.

    apple03
    banana01
    cherry02
    

    Alternatively you could output the results to a variable and call the fruit you need from there if you don't need the whole list as output.

    # Group by fruit and then we can find the next available index within the groups
    $availableIndexes = $fruityArray | Group-Object Fruit | ForEach-Object{
        # For this fruit determine the next available index
        $thisFruitGroup = $_
    
        # Determine the highest index value. We add one in case all indexes are present from 1 to highest
        $highestPossibleIndex = ($thisFruitGroup.Group.Index | Measure-Object -Maximum).Maximum + 1
    
        # Check all possible indexes. Locating all that are free but filter the first one out
        $nextAvailableIndex = 1..$highestPossibleIndex | Where-Object{$_ -notin $thisFruitGroup.Group.Index} | Select -First 1
    
        # Take the fruit and add a padded index then pass that value to the pipeline. 
        [pscustomobject][ordered]@{
            Fruit = $thisFruitGroup.Name
            Index = $nextAvailableIndex
            String = '{0}{1:00}'-f $thisFruitGroup.Name, $nextAvailableIndex
        }
    }
    
    $availableIndexes | Where-Object{$_.Fruit -eq "Apple"}  | Select-Object -ExpandProperty String
    

    Which would net the output of:

    apple03
    
    0 讨论(0)
  • 2021-01-26 02:47

    This seems to do the trick!

    ## Create variable to store number in 
    $spareNumber = $null 
    ## we are presuming that they have already been seperated into groups 
    $apples = @("apples01","apples002","apples3","apples15") 
    ## create an empty array 
    $num = @() 
    ## You know what a foreach is right? ;) 
    foreach ($apple in $apples)
    {
        ## the hard working part 
        ## [convert]:: toint32 converts to, you guessed it... (and adds it to $num)
        ## $apple -split ($apple -split '\d+$') < split all digits from end, then strip off everything at the front 
        $num += [convert]::ToInt32([string]$($apple -split ($apple -split '\d+$'))[1], 10)
    }
    ## count from 1 to 10, and pass to foreach 
    (1..10) | foreach {
        ##'when we find one that isn't in $num, store it in sparenumber and break out of this joint. 
        if (!$num.Contains($_)) {
            $spareNumber = $_ 
            break 
        }
     }
     ## and here is your number... 
     $spareNumber 
    
    0 讨论(0)
  • 2021-01-26 02:48

    if the name that occurs first is pure letters not including any number and than followed by a number . that would be easy and you can get the index of the first number or char that exists in that char list {1,2,3,4,5,6,7,8,9} and than you can make substring(0,indexof(firstnumber))

    0 讨论(0)
  • 2021-01-26 03:02

    The naive and straight-forward solution would be based on pre-generating a list of syntax valid names.

    Query names that are already in use and store the results into a collection.

    Iterate the used names collection and remove those from the pre-generated collection.

    Sort the pre-generated collection.

    Now you got a collection that contains unused names in sorted order. Pick any number of desired names for further usage.

    0 讨论(0)
提交回复
热议问题