在一个LINQ语句中选择值并为其附加数字?

时间:2013-05-13 15:23:40

标签: c# linq

我的数据库中有以下两个名称:SMITHSMITH1

如果某个名称在数据库中退出,我想在只有SMITH退出的情况下向其附加1,如果已经有一个数字的名称已经退出,我想增加该名称的数字部分。 / p>

是否可以在一个LINQ状态中执行此操作?现在,我在做:

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);
    }
}

由于我的while循环中有LINQ查询,每次循环时它是否会进行选择?

此外,如果有人知道如何使这更简洁,但可读,这将是伟大的?

这适用于没有数字或1 - 9的名字,但是当我达到10时会发生什么,它只会替换最后一个字符,在这种情况下为0,我该如何处理?

有没有办法在LINQ中获取数字部分,因此SMITH12会返回12

5 个答案:

答案 0 :(得分:0)

这是一种非常天真,但易于阅读的方式来做你想做的事情:

//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

有许多方法可以提高效率,有些方法会牺牲可读性。

如果需要,我会将此代码的优化作为练习留给您。

答案 1 :(得分:0)

您的代码似乎不正确,无法编译。

这应该有效:

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";
}

这将检查一个或多个对象“Name是否以给定名称开头。如果确实如此,则第一个linq查询检查结尾是否存在带有数字的重复项。然后它将按此编号desc排序并选择第一个(具有最高编号)。新名称将是名称+最高编号+ 1。否则它只会使用名称+“2”,因为它是第二个名称。

答案 2 :(得分:0)

使用类似的东西。

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();

请注意existingNamessuffix枚举一次existingNames。我建议使用IEnumerable<string>的HashSet而不是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();

{{1}}

答案 3 :(得分:0)

这将检索下一个名称(例如,如果最近的增量为NAME10,则下一个名称为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
}

答案 4 :(得分:0)

这些方面应该是你做的事情:

迭代你的可列举名单。对于每个这样的名称,

  • 将其拆分为组成组件(基本名称和可选的数字后缀)
  • 丢弃基本名称与所需名称不匹配的任何项目
  • 找到剩余集合的最高后缀值(可能没有)。

如果找到最大后缀,请为其添加1并将其附加到所需名称,否则按原样返回所需名称。

示例:

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() : "" ) ;
}