在一条LINQ语句中选择value并向其追加number
本文关键字:追加 number value 选择 一条 LINQ 语句 | 更新日期: 2023-09-27 18:13:15
我的数据库中有以下两个名称:SMITH
和SMITH1
如果一个名字在数据库中存在,如果只有SMITH
存在,我想在它后面附加一个1,如果一个名字已经有一个数字存在,我想增加名字的数字部分。
有可能在一个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);
}
}
因为我有LINQ查询在我的while循环,它会做一个选择每次它必须循环回来吗?
还有,如果有人知道一种方法,使这更简洁,但可读,那将是伟大的?
对于没有数字或1 - 9的名称确实有效,但是当我到达10时,它只会替换最后一个字符,在本例中是0,我该如何处理?
是否有办法在LINQ中获得数字部分,因此SMITH12
将返回12
您的代码似乎不正确,无法编译。
这个应该可以工作:
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排序,并选择第一个(数字最高的)。新名称将是名称+ highestnumber+1。否则,它将只使用名称+ "2",因为它是第二个名称。
这样写。
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();
注意existingNames
在每个suffix
中被枚举一次。我建议对existingNames
使用HashSet,而不是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();
这将检索下一个名字(例如,如果最近的增量是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
}
您应该这样做:
遍历可枚举的名称列表。对于每个这样的名称,
- 将其拆分为其组成组件(一个基本名称和一个可选的数字后缀)
- 丢弃任何基本名称与期望名称不匹配的物品
- 查找剩余集合的最高后缀值(可能为none)。
如果您发现了一个最大后缀,将其加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() : "" ) ;
}
这是一种非常简单,但易于阅读的方法来完成您想要做的事情:
//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
有很多方法可以提高效率,有些方法会以牺牲可读性为代价。
我将把这段代码的优化留给您作为练习,如果需要的话。