C++ 以与另一个列表相同的方式重新排列列表
我偶然发现了一个页面,其中有很多类别,每个类别旁边都有每个类别中的项目数量,用括号括起来。一些非常普通的东西。看起来是这样的:C++ 以与另一个列表相同的方式重新排列列表,c++,sorting,c++11,C++,Sorting,C++11,我偶然发现了一个页面,其中有很多类别,每个类别旁边都有每个类别中的项目数量,用括号括起来。一些非常普通的东西。看起来是这样的: Category 1 (2496) Category 2 (34534) Category 3 (1039) Category 4 (9) ... 所以我很好奇,我想看看哪些类别有更多的项目等等,因为所有类别都在页面中,所以我可以选择所有类别并将它们复制到文本文件中,使事情变得非常简单 我制作了一个小程序,读取所有的数字,将它们存储在一个列表中,并对它们进行排序。为了
Category 1 (2496)
Category 2 (34534)
Category 3 (1039)
Category 4 (9)
...
所以我很好奇,我想看看哪些类别有更多的项目等等,因为所有类别都在页面中,所以我可以选择所有类别并将它们复制到文本文件中,使事情变得非常简单
我制作了一个小程序,读取所有的数字,将它们存储在一个列表中,并对它们进行排序。为了知道它属于哪一类,我只需在浏览器中输入数字
但我认为在我的文本文件中,在数字旁边有类别的名称会很好,我设法在另一个文件中解析了它们。然而,很明显,它们不是订购的
到目前为止,我能做的就是:
bool is_number(const string& s) {
return !s.empty() && find_if(s.begin(), s.end(), [](char c) { return !isdigit(c); }) == s.end();
}
int main() {
ifstream file;
ofstream file_os, file_t_os;
string word, text; // word is the item count and text the category name
list<int> words_list; // list of item counts
list<string> text_list; // list of category names
file.open("a.txt");
file_os.open("a_os.txt");
file_t_os.open("a_t_os.txt");
while (file >> word) {
if (word.front() == '(' && word.back() == ')') { // check if it's being read something wrapped in parenthesis
string old_word = word;
word.erase(word.begin());
word.erase(word.end()-1);
if (is_number(word)) { // check if it's a number (item count)
words_list.push_back(atoi(word.c_str()));
text.pop_back(); // get rid of an extra space in the category name
text_list.push_back(text);
text.clear();
} else { // it's part of the category name
text.append(old_word);
text.append(" ");
}
} else {
text.append(word);
text.append(" ");
}
}
words_list.sort();
for (list<string>::iterator it = text_list.begin(); it != text_list.end(); ++it) {
file_t_os << *it << endl;
}
for (list<int>::iterator it = words_list.begin(); it != words_list.end(); ++it) {
file_os << fixed << *it << endl;
}
cout << text_list.size() << endl << words_list.size() << endl; // I'm getting the same count
}
按照我的方式,我将有一个列表
包含以下内容:{10,6,5,3}
和一个列表
包含以下内容:{a,B,C,D}
我想说的是,我想找到一种方法来跟踪第一个列表中元素的重新排列方式,并将这种模式应用到第二个列表中。重新排列的模式是什么?它将是:第一个项目(5)进入第三个位置,第二个项目(3)进入第四个位置,第三个项目(10)进入第一个位置,依此类推。。。。然后这个模式应该应用到另一个列表中,这样它就会变成这样:{C,D,A,B}
问题是跟踪模式,并将其应用到下面的列表中
我有什么办法可以做到这一点吗?有什么特别的功能可以帮助我吗?任何跟踪所有交换和交换的方法排序算法都可以这样做,因此它可以应用于大小相同的不同列表?另一种排序算法呢
我知道这可能效率很低,是个坏主意,但这似乎是一个小挑战
我还知道,我可以将string
和int
、category和item count在某种容器中配对,比如pair
或map
,或者创建一个我自己的容器类,并根据项目计数对项目进行排序(我想map
将是最佳选择,你认为呢?),但这不是我要问的。最好的方法是创建一个列表,其中包含您要在自定义排序函数中排序和馈送的两组信息
例如:
struct Record {
string name;
int count;
};
list<Record> myList;
sort(myList, [](Record a, Record b){
return a.count < b.count;
});
struct记录{
字符串名;
整数计数;
};
列出我的清单;
排序(myList,[](记录a,记录b){
返回a.count
在一般情况下,管理一个复杂数据类型列表总比单独管理两个或多个简单数据类型列表要好,尤其是当它们是可变的时。还有一些改进方法:
首先,请注意:
- 建议将类别名称和项目存储在一起,以确保清晰、易于阅读代码等
- 最好使用
std::vector
而不是std::list
(请参阅)
- 代码以问题中指定的格式加载文件,并将信息对存储在向量中
- 使用
std::sort
函数仅按项目编号进行排序(具有相同项目的类别将以任何顺序排序,如果您要为类别名称排序,则具有相同项目的类别将lambda正文更改为返回std::tie(left.items,left.name)>std::tie(right.items,right.name);
- 添加了一个版本,其中包含信息拆分、一个集合项和索引(将项与名称关联)信息以及其他名称信息
代码:
列表不支持随机访问迭代器,因此这将是一个问题,因为列表不能基于向量(或数组)进行排列索引,而无需来回执行大量列表遍历来模拟随机访问迭代。NetVipeC的解决方案是使用向量而不是列表来解决此问题。如果使用向量,则可以生成向量(或数组)对要排序的向量进行索引排序,然后使用自定义比较运算符对向量索引进行排序。然后,您可以根据已排序索引的向量复制向量。也可以根据索引对向量进行重新排序,但该算法也会对索引的向量进行排序,因此您必须复制已排序的索引ndices(对第二个向量进行排序),或按已排序的索引顺序复制每个向量
如果确实要使用列表,可以实现自己的std::list::sort,这将对两个列表执行相同的操作。Microsoft版本的std::list::sort使用一个列表数组,其中数组中的节点数为[i]=2^i,它一次将一个节点合并到数组中,然后在处理所有节点时,它合并数组中的列表以生成一个排序列表。您需要两个数组,每个列表一个进行排序。如果您愿意,我可以为这种类型的列表排序发布示例C代码。很抱歉,我不知道您在说什么……我更新了我的举个例子提问,也许会有帮助。解释我试图实现的目标并不是那么容易。然后回答你的问题,答案是否定的。std::sort不会公开这些信息。而且,尝试这样做几乎肯定是错误的方法。不过,如果你这么想,当然,你可以实现自己的方法sort函数来做这个。我自己的函数来做什么?你自己的sort函数来生成一个排序列表和一个INT列表,将源索引映射到目标索引。然后是另一个自定义函数来应用它。当然,我仍然认为你永远不应该在实际代码中这样做。标准库中没有实用程序来做。但这不是不可能的。我知道我永远不应该这样做,这是一个可怕的想法。问题是
struct Record {
string name;
int count;
};
list<Record> myList;
sort(myList, [](Record a, Record b){
return a.count < b.count;
});
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
bool is_number(const std::string& s) {
return !s.empty() &&
find_if(s.begin(), s.end(), [](char c) { return !isdigit(c); }) ==
s.end();
}
struct category_info {
std::string name;
int items;
};
struct category_items_info {
int items;
size_t index;
};
int main() {
std::ifstream file("H:\\save.txt");
std::vector<category_info> categories;
std::vector<category_items_info> categories_items;
std::vector<std::string> categories_names;
std::string word;
std::string text;
while (file >> word) {
if (word.front() == '(' && word.back() == ')') {
std::string inner_word = word.substr(1, word.size() - 2);
if (is_number(inner_word)) {
std::string name = text.substr(0, text.size() - 1);
int items = atoi(inner_word.c_str());
categories.push_back(category_info{name, items});
categories_names.push_back(name);
categories_items.push_back(
category_items_info{items, categories_items.size()});
text.clear();
} else { // it's part of the category name
text.append(word);
text.append(" ");
}
} else {
text.append(word);
text.append(" ");
}
}
std::sort(categories.begin(), categories.end(),
[](const category_info& left, const category_info& right) {
return left.items > right.items;
});
std::sort(
categories_items.begin(), categories_items.end(),
[](const category_items_info& left, const category_items_info& right) {
return left.items > right.items;
});
std::cout << "Using the same storage." << std::endl;
for (auto c : categories) {
std::cout << c.name << " (" << c.items << ")" << std::endl;
}
std::cout << std::endl;
std::cout << "Using separated storage." << std::endl;
for (auto c : categories_items) {
std::cout << categories_names[c.index] << " (" << c.items << ")"
<< std::endl;
}
}
Using the same storage.
Category 2 (34534)
Category 1 (2496)
Category 3 (1039)
Category 4 (9)
Using separated storage.
Category 2 (34534)
Category 1 (2496)
Category 3 (1039)
Category 4 (9)