【发布时间】:2020-05-14 10:56:33
【问题描述】:
我在 C# 中有以下代码来计算集合的分区
取自 (How to find all partitions of a set)
public static IEnumerable<List<List<T>>> GetAllPartitions<T>(T[] elements) {
var lists = new List<List<T>>();
var indexes = new int[elements.Length];
lists.Add(new List<T>());
lists[0].AddRange(elements);
for (;;) {
yield return lists;
int i,index;
for (i=indexes.Length-1;; --i) {
if (i<=0)
yield break;
index = indexes[i];
lists[index].RemoveAt(lists[index].Count-1);
if (lists[index].Count>0)
break;
lists.RemoveAt(index);
}
++index;
if (index >= lists.Count)
lists.Add(new List<T>());
for (;i<indexes.Length;++i) {
indexes[i]=index;
lists[index].Add(elements[i]);
index=0;
}
}
我的任务是将此代码移植到 C++。不幸的是,yield 关键字让我失望了。
在此部分:
for (;;) {
yield return lists;
这里发生了什么?如果我删除 yield 关键字,代码将不起作用。这段代码也不是递归的,所以我不知道这里发生了什么
编辑:
好的,我将它移植到 C++。谢谢大家:
std::vector<std::vector<std::vector<int>>> getPartitions(const std::vector<int>& elements){
std::vector<std::vector<std::vector<int>>> fList;
std::vector<std::vector<int>> lists;
std::vector<int> indexes(elements.size(), 0); // Allocate?
lists.emplace_back(std::vector<int>());
lists[0].insert(lists[0].end(), elements.begin(), elements.end());
int counter = -1;
for(;;){
counter += 1;
fList.emplace_back(lists);
int i,index;
bool obreak = false;
for (i=indexes.size()-1;; --i) {
if (i<=0){
obreak = true;
break;
}
index = indexes[i];
lists[index].erase(lists[index].begin() + lists[index].size()-1);
if (lists[index].size()>0)
break;
lists.erase(lists.begin() + index);
}
if(obreak) break;
++index;
if (index >= lists.size())
lists.emplace_back(std::vector<int>());
for (;i<indexes.size();++i) {
indexes[i]=index;
lists[index].emplace_back(elements[i]);
index=0;
}
}
return fList;
}
int main()
{
std::vector<int> elements = {0,1,2,3,4,5};
auto fLists = getPartitions(elements);
for(auto& lists : fLists){
for(auto& l : lists){
std::cout << "(";
for(auto& e : l){
std::cout << e << " ";
}
std::cout << ") ";
}
std::cout << std::endl;
std::cout << "--" << std::endl;
}
return 0;
}
【问题讨论】:
-
这不是我所说的好 C# 代码(我对那个 for 循环一点也不满意)。收益返回允许一次计算 IEnumerable 中的单个项目。你应该可以从微软docs.microsoft.com/en-us/dotnet/csharp/language-reference/…了解你需要的东西
-
好吧,我想是时候咬紧牙关,在这种情况下理解收益率了。从未想过将一个函数移植到 C++ 会导致一整天的工作
-
可能最令人困惑的部分是内容不代表一个函数,它们代表一个类。函数的所有内部状态最终都在一个隐藏类中,该类跟踪它在执行中的位置和所有变量。 yield return 的强大功能使得在没有它的语言中进行模拟需要做很多工作。
-
@raaj 查看
co_yield表达式,它是 C++20 规范的一部分。