我有一组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 ++(不做语言垃圾邮件!)
答案 0 :(得分:2)
正数:
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();
答案 1 :(得分:1)
我一直在玩这个想法,到目前为止似乎有效。当然,我不得不稍微修改你的数据集,因为事实上,没有数字通过了只有正面或负面的测试。
所以,这里是:
//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内容重写为一个长查询。
干杯
答案 2 :(得分:0)
为什么不编写一个简单的方法来获取一个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更改为简单的枚举,以使其更具可读性......)
答案 3 :(得分:0)
既然你提到过你可能想要一个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
值,具体取决于输入整数的符号。如果对BOTH
的调用是带有相反符号的整数,则这两个状态将分别仅变为modify
状态。
最好的部分是你只需要遍历一组列表,然后你就 all 整数分组。
这可以通过c ++ 14中提供的ranged-for语法巧妙地完成:
std::unordered_map<int, SignRecord>
intOrganizer;
for(auto &&subList : myInts){
for(auto &&entry : subList){
intOrganizer[absolute(entry)].modify(entry);
}
}
coliru演示位于here。请注意,我修改了您的给定输入列表,因为每个输入整数似乎都用列表列表中的两个符号表示。
答案 4 :(得分:-1)
以这种方式创建自己的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));