Select a value and add it to a single LINQ statement?

I have the following two names in my database: SMITH and SMITH1

If the name comes out in the database, I want to either add 1 to it, if only SMITH quits, and if the name with the number is already completed, I want to increase the digital part of the name.

Is it possible to do this in the same LINQ status? Right now, I am doing:

 string name = string.Format("{0}{1}{2}",first_name,middle_name,last_name).ToUpper(); //Check for duplicates while(names.SingleOrDefault (d => d.Name== name) != null) { //Get last char char lastChar = name[name.Length - 1]; //Last char is number if(Char.IsNumber(lastChar)) { name = name.Replace(lastChar,Convert.ToChar(Convert.ToInt32(lastChar) + 1)); } else { name = (name + 1); } } 

Since I have a LINQ query in my while loop, will it select every time it has to loop back?

Also, if anyone knows a way to make it more concise but readable, would that be great?

This works for names that either don't have a number, or 1 to 9, but what happens when I get to 10 it only replaces the last character, in this case 0, how do I do it?

Is there any way to get the numeric part in LINQ, so SMITH12 will return 12

+4
source share
5 answers

Here's a very naive but easy to read way to do what you are looking for:

 //Check for duplicates bool nameValid = names.SingleOrDefault (d => d.Name == name) == null; int count = 1; while(!nameValid) { if( names.SingleOrDefault (d => d.Name == name + count.ToString()) == null ) { name = name + count.ToString(); nameValid = true; } else { count++; } } // name now contains a unique name 

There are several ways to make this more efficient, some at the cost of readability.

I will leave optimizing this code as an exercise for you if you need it.

0
source

Your code seems to be wrong and does not compile.

This should work:

 var sameNames = names .Where(n => n.Name.Length >= name.Length && n.Name.Substring(0,name.Length)==name); if (sameNames.Any()) { var lastNameWithNumber = sameNames .Where(n => Char.IsDigit(n.Name.Last())) .Select(n => new { n.Name, Num = int.Parse(new string(n.Name.Reverse().TakeWhile(Char.IsDigit).Reverse().ToArray())) }) .OrderByDescending(x => x.Num) .FirstOrDefault(); if (lastNameWithNumber != null) name = name + (lastNameWithNumber.Num + 1); else name = name + "2"; } 

This checks to see if one or more Name objects begin with the given name. If so, then the first linq query checks to see if there are duplicates with numbers at the end. Then he will order desc by this number and select the first (with the largest number). The new name will have the name + highest number + 1. Otherwise, it will simply use the name + "2", as this is the second name.

0
source

Use something like this.

 IEnumerable<string> existingNames = ...; string rawName = ...; string finalName = (from suffix in Enumerable.Range(0, int.MaxValue) let testName = rawName + (suffix == 0 ? "" : suffix.ToString()) where existingNames.All(n => n != testName) select testName).FirstOrDefault(); 

Note that existingNames listed once per suffix . I would recommend using a HashSet for existingNames instead of IEnumerable<string> .

 HashSet<string> existingNames = ...; string rawName = ...; string finalName = (from suffix in Enumerable.Range(0, int.MaxValue) let testName = rawName + (suffix == 0 ? "" : suffix.ToString()) where !existingNames.Contains(testName) select testName).FirstOrDefault(); 
0
source

This will result in the following name (for example, if the most recent increment is NAME10, the next name will be NAME11):

 int tmp; var existingNames = from name in names let numericIndex = name.IndexOfAny(new char[] {'1','2','3','4','5','6','7','8','9','0'}, 0) let subName = numericIndex > -1 ? name.Substring(0, numericIndex) : name let IndexAsString = numericIndex > -1 ? name.Substring(numericIndex) : "0" let index = int.TryParse(IndexAsString, out tmp) ? tmp : 0 group new { subName, index } by subName into gs select gs; var newNames = from existingName in existingNames select new { BaseName = existingName.Key, Index = existingName.Max(a => a.index) + 1 }; if (newNames.Any(a => a.BaseName == nameToAdd)) { // do your work to change the name } 
0
source

Something in this direction should be to you:

Iterate over your enumerated list of names. For every such name

  • divide it into its component parts (base name and optional numeric suffix)
  • toss any elements where the base name does not match the desired name
  • find the highest suffix value for the remaining set (which may be nothing).

If you find the maximum suffix, add 1 to it and add it to the desired name, otherwise return the desired name as it is.

Example:

 private static readonly Regex rxNameSuffix = new Regex( @"^(?<name>.+)(?<suffix>\d*)$" ) ; string GenerateName( string name , IEnumerable<string> existingNames ) { if ( string.IsNullOrWhiteSpace(name) ) throw new ArgumentException("name") ; int? maxSuffix = existingNames.Select( s => { Match m = rxNameSuffix.Match(s) ; if ( !m.Success ) throw new InvalidOperationException("that shouldn't have happened") ; string pfx = m.Groups["name"].Value ; int? sfx = m.Groups["suffix"].Value.Length == 0 ? (int?)null : int.Parse( m.Groups["suffix"].Value ) ; return new Tuple<string,int?>( pfx , sfx ) ; }) .Where( x => name.Equals( x.Item1 , StringComparison.OrdinalIgnoreCase) ) .Aggregate( (int?)null , (acc,x) => { int? newacc ; if ( !x.Item2.HasValue ) return acc ; return !acc.HasValue || acc.Value < x.Item2.Value ? x.Item2 : acc ; }) ; int? suffix = maxSuffix.HasValue ? maxSuffix+1 : null ; return name + ( suffix.HasValue ? suffix.ToString() : "" ) ; } 
0
source

Source: https://habr.com/ru/post/1480514/


All Articles