检查在List<;列表<;int>>;高效
本文关键字:gt lt 高效 int 列表 List 检查 | 更新日期: 2023-09-27 18:00:21
我有一组List<List<int>>
数据,字符串表示如下(给出想法!):
{{1,3},{-1,-3},{2,5},{-2,-5},{-3,4},{-5,4},{3,5,-4},{6,-8},{7,-8},{-6,-7,8},{7,9},{-7,-9},{3,8,-10},{-3,-8,-10},{-3,8,10},{3,-8,10},{4,9,-11},{-4,-9,-11},{-4,9,11},{4,-9,11},{10,11},{-1,6},{1,-6},{-2,7},{2,-7}}
我想检查,在所有现有的数字中,是否存在一个仅以正形式存在的数字或一组数字。我的意思是,如果在整个数据中有3和-3,我应该返回false,否则我必须将3作为仅以正3存在的数字添加到另一个列表中。(只有否定的数字也是如此)
以下是我尝试的方法:
首先,生成一组唯一的数字并删除负数:
private void GenerateCurrentExistingVariables()
{
_uid = new List<int>();
var all = _cnf.Data.SelectMany(list => list).ToList();
_uid = all.Distinct().ToList(); //make list unique
_uid.Sort(); //sort numbers
_uid.Reverse(); //reverse so highest numbers would evalaute first!
_uid = _uid.Where(i => i >= 0).ToList(); //remove negative numbers
}
然后我做这样的事情:
在一个方法中,我调用以下代码:
for (var i = 0; i < _uid.Count; i++)
{
if (ExistOnlyInNegatedForm(_uid[i]))
{
onlyNegatedList.Add(_uid[i]);
}
//perhaps continue
if (ExistOnlyInPositiveForm(_uid[i]))
{
onlyPositiveList.Add(_uid[i]);
}
}
依次调用以下方法:
private bool ExistOnlyInPositiveForm(int id)
{
for (var i = 0; i < _cnf.Data.Count; i++)
{
for (var j = 0; j < _cnf.Data[i].Count; j++)
{
if (_cnf.Data[i][j] == id)
{
return false;
}
}
}
return true;
}
private bool ExistOnlyInNegatedForm(int id)
{
var toCheck = -id;
for (var i = 0; i < _cnf.Data.Count; i++)
{
for (var j = 0; j < _cnf.Data[i].Count; j++)
{
if (_cnf.Data[i][j] == -toCheck)
{
return false;
}
}
}
return true;
}
对于这个简单的任务来说,这太多的代码了,我觉得随着数据越来越大,这会越来越慢。。。请告诉我该如何改进。此外,我希望使用LINQ来完成这项工作,至少是为了减少代码行数!
我也想看到一个C++解决方案,所以我在我的问题中标记C++(不是做语言垃圾邮件!)
对于正数:
var uids = _uid.SelectMany(q => q).ToArray();
var positive = uids.Where(p => p >= 0).Distinct()
.Except(uids.Where(p => p < 0).Select(p => -p))
.ToList();
return positive.Any();
对于负数:
var negative = uids.Where(p => p < 0).Distinct()
.Except(uids.Where(p => p >= 0).Select(p => -p))
.ToList();
return negative.Any();
我一直在考虑这个想法,到目前为止,这个想法似乎奏效了。当然,我不得不稍微修改你的数据集,因为事实上,没有一个数字通过了只有阳性或阴性的测试。
所以,这是:
//Setting up the mock data
List<List<int>> data = new List<List<int>>();
data.Add(new List<int>(new[] { 1, 3 }));
data.Add(new List<int>(new[] { -1, -3 }));
data.Add(new List<int>(new[] { 2, 5 }));
data.Add(new List<int>(new[] { -2, -5 }));
data.Add(new List<int>(new[] { -3, 4 }));
data.Add(new List<int>(new[] { -5, 4 }));
data.Add(new List<int>(new[] { 3, 5, -4 }));
data.Add(new List<int>(new[] { 6, -8 }));
data.Add(new List<int>(new[] { 7, -8 }));
data.Add(new List<int>(new[] { -6, -7, 8 }));
data.Add(new List<int>(new[] { 7, 9 }));
data.Add(new List<int>(new[] { -7, -9 }));
data.Add(new List<int>(new[] { 3, 8, -10 }));
data.Add(new List<int>(new[] { -3, -8, -10 }));
data.Add(new List<int>(new[] { -3, 8, 10 }));
data.Add(new List<int>(new[] { 3, -8, 10 }));
data.Add(new List<int>(new[] { 4, 9, -11 }));
data.Add(new List<int>(new[] { -4, -9, -11 }));
data.Add(new List<int>(new[] { -4, 9, 11 }));
data.Add(new List<int>(new[] { 4, -9, 11 }));
data.Add(new List<int>(new[] { 10, 11 }));
data.Add(new List<int>(new[] { -1, 6 }));
data.Add(new List<int>(new[] { 1, -6 }));
data.Add(new List<int>(new[] { -2, 7 }));
data.Add(new List<int>(new[] { 2, 39 }));
//Actual solution code
var all = data.SelectMany(l => l); //flatten
var grouped = all.GroupBy(g => Math.Abs(g)); //Group
//Look for groups where the Sum is equal Key * Count,
//which means only either all positives, or all negatives
var good = grouped.Where(i => i.Key * i.Count() == Math.Abs(i.Sum()));
var result = good.Select(g => g.First()); //Get rid of groups
var allPos = result.Where(i => i > 0); //Self explanatory
var allNeg = result.Where(i => i < 0);
我已经拆分了每个步骤,但可以很容易地将linq内容重写为一个长查询。
干杯
你为什么不写一个简单的方法,它会接受一个int列表,一个布尔值,表示你想要正和负,它只会返回true-false
通过这种方式,您可以遍历外部列表,为其中的每个元素调用它,如果您得到了所需的内容,则从那里继续:
public int AllSameSign(IEnumerable<int> theInputList, bool positive = true)
{
if (positive)
return theInputList.All(i=>i >= 0);
else
return theInputList.All(i=>i < 0);
}
(这是我的想法,你可以把bool改成一个简单的枚举,让它更可读…)
既然你提到你可能想要一个c++答案,我就写了一个。它使用哈希表来存储整数的绝对值的键值对,以及存储该特定绝对值历史的对象。
历史跟踪对象定义如下:
int sign(int a){return ((a > 0) - (a < 0));}
int absolute(int a){return a * sign(a);}
struct SignRecord{
SignRecord() : value_{NEITHER}{}
enum SignGrouping{
NEITHER, NEGATIVE, POSITIVE, BOTH
} value_;
SignGrouping& modify(int modifier){
auto intToGrouping = [](int a)->SignGrouping {return a < 0 ? NEGATIVE : POSITIVE;};
if(value_ == NEITHER){value_ = intToGrouping(modifier);}
else if(value_ == BOTH){return value_;}
else if(value_ == intToGrouping(modifier)){return value_;}
else{
return value_ = BOTH;
}
return value_;
}
};
由于哈希表需要默认构造对象,以便按键引用表中的元素,这就是我选择在哈希表中插入和修改元素的方式,因此有一个默认构造函数,其状态存储一个既没有找到正值也没有找到负值的指示符。但是,只有在没有调用"修改"值的情况下,这种状态才会持续。我立即调用modify
成员函数,这样它就不会出现在最终输出中。
modify
函数根据输入整数的符号将NEITHER
值转换为NEGATIVE
或POSITIVE
值。只有当对modify
的调用是一个符号相反的整数时,这两种状态才会分别变为BOTH
状态
最好的部分是,您只需要在列表集中迭代一次,然后您就可以所有整数分组。
这可以通过c++14:中可用的语法范围巧妙地完成
std::unordered_map<int, SignRecord>
intOrganizer;
for(auto &&subList : myInts){
for(auto &&entry : subList){
intOrganizer[absolute(entry)].modify(entry);
}
}
coliru演示位于此处。请注意,我修改了您给定的输入列表,因为在列表列表中,每个输入整数似乎都用两个符号表示。
只需以这种方式创建自己的IEquality比较器:
class OnlyPositiveInt : IEqualityComparer<int>
{
public bool Equals(List<int> some)
{
if ( some.First() > 0 && some.Last() > 0) { return true; }
return false;
}
public int GetHashCode(int x)
{
return x.GetHashCode();
}
}
List<List<int>> onlyPositive = new List<List<int>>(generatedList.Distinct(OnlyPositiveInt));