我有IEnumerable<int>
,其中包含所有现有ID。我想生成一个新的id,它是现有ID中不存在的任何int
。我有一个黑客攻击解决方案,但我想知道最好的方法来做到这一点。
// Inefficient solution
public static int GetFreshId(this IEnumerable<int> existingIds)
{
int i = Int32.MinValue;
while (existingIds.Contains(i)) // There is a case where all ids are taken!
{
i += 1;
}
return i;
}
更新:此处最佳定义为:
IEnumerable
实施,对某些人来说,比其他人更快答案 0 :(得分:3)
如果您不在乎使用最低免费 ID,您可以直接使用当前最大ID的继承者:
import UIKit
extension Notification.Name
{
enum MyNames
{
static let Hello = Notification.Name(rawValue: "HelloThere")
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.post(name: Notification.Name.MyNames.Hello ,object: nil, userInfo: nil)
}
}
如果已经包含public static int GetFreshId(this IEnumerable<int> existingIds)
{
return existingIds.Max() + 1;
}
和 Int32.MaxValue
,则会出现问题,因此您需要针对此案例进行一些特殊处理。
但是看到Int32.MinValue
范围内存在多少个ID,这应该很少发生,因此可以为该角落案例实施更昂贵的算法。
如果您害怕溢出,可以先改进序列,然后扫描间隙(而不是测试每个可能的Int32
- 值),从而改进第一种方法:
int
编辑:感谢伊万打败了我的大错,相应改进了第二种方法
答案 1 :(得分:1)
您的解决方案的问题是这一行代码在循环中执行:
existingIds.Contains(i)
这具有O(N2)的复杂性。改进它的一种方法是使用与哈希而不是索引一起使用的集合。例如HashSet<T>
:
public static int GetFreshId(this IEnumerable<int> existingIds)
{
var hashedIds = new HashSet<int>(existingIds);
int i = Int32.MinValue;
while (hashedIds.Contains(i)) ++i; // now it use fast O(1) lookups
return i;
}
答案 2 :(得分:1)
我只想添加一些异常处理。这不会在范围内丢失数字。
public static int GetFreshId(this IEnumerable<int> existingIds)
{
if (existingIds == null) {
throw new ArgumentNullException(nameof(existingIds));
}
if (!existingIds.Any()){
return int.MinValue;
}
var lastId = existingIds.Max();
if (lastId == Int.MaxValue){
throw new ApplicationException("Sorry there are no more int available. Consider switching to int64.");
}
return lastId+1;
}
答案 3 :(得分:0)
如果你确定你永远不会有那么多你的Id等于Int32.MaxValue的项目,那么下面的内容会足够快
public static int GetFreshId(this IEnumerable<int> existingIds)
{
return existingIds.Max() + 1;
}
答案 4 :(得分:0)
如果您的ID列表中没有任何空白
public static int GetFreshId(IEnumerable<int> existingIds) {
if (existingIds.Any()) {
int i = existingIds.Max();
if (i == Int32.MaxValue) {
throw new Exception("Ups...");
}
return i++;
}
return 1; // or what else
}
如果您可能认为您的解决方案没问题,可能只需添加检查以避免溢出