【问题标题】:Merging duplicates in different lines of a text file合并文本文件不同行中的重复项
【发布时间】:2018-10-16 19:10:17
【问题描述】:

我有一个文本文件,其中一行上的第一个数字是图表的节点号,第二个数字是连接到第一个节点的节点号。第三个数字是边的权重。

这是一个示例,文件中的两行包含 3 和 5,权重为 0.5:

    1 3 0.5
    3 5 0.5
    3 6 0.5
    3 5 0.5
    6 8 0.5
    4 6 1

我希望能够将它们合并成一条与 3 和 5 有连接的线,但将权重更新为它们权重的总和(在本例中为 1)。然后应该删除重复的行。

所以我想检查重复的节点对,如果发现重复的节点对所有节点的总权重相加,然后更新该对的一行以获得正确的总权重,然后删除所有其他行节点。

我已经为 Edges 做了一个结构:

struct Edge {
    int c1, c2;
    float weight;
};

我已阅读文件并将它们全部放入此结构中:

if (updateGraph.is_open()) {
    string data[3];
    Edge e;

    while (getline(updateGraph, stri)) {
        stringstream in(stri);
        int i = 0;
        while (in.good() && i < 3) {
            in >> data[i];
            i++;
        }
        e.c1 = atoi(data[0].c_str());
        e.c2 = atoi(data[1].c_str());
        e.weight = atof(data[2].c_str());
        cout << e.c1 << " " << e.c2 << " " << e.weight << endl;
    }
}

但现在我不确定如何比较它们以查看是否有任何边缘具有相同的 c1 和 c2。我该怎么做?

【问题讨论】:

  • 如果您需要代码方面的帮助,我们需要查看代码。另请阅读minimal reproducible example
  • 我无法理解这里提出的问题。
  • 提示:你使用struct connection { int first,second; double weight; } 总是先存储较小的索引
  • @user463035818 好的,我知道我会怎么做,这使得比较它们变得更加简单。一旦找到重复项,我就会明白如何使用该方法找到总重量,但我将如何知道要删除文本文件中的哪一行?
  • 为什么要从输入文件中删除任何内容?如果您需要将结果输出写入文件,那么就这样做,但保留输入文件原样

标签: c++ arrays file-io


【解决方案1】:

我已阅读文件并将它们全部放入此结构中:[...] 但现在我不确定如何比较它们以查看是否有任何边缘具有相同的 c1 和 c2。

从逻辑上讲,您知道您需要做的不仅仅是读取边缘并将其打印出来。你的程序必须保留一些它到目前为止看到的边缘的记忆。例如,它可能必须将第一行的边与最后一行合并。

我该怎么做?

没有单一的“正确”方法可以做到这一点。但是,如果您尝试创建自己的类,就像您定义的 Edge 结构一样,那么您将不得不编写更多代码。例如,要使用std::set 集合,您需要a comparison operator(请注意,C++ 甚至不提供默认的equality operator。)

如果您避免创建自定义结构,C++ 可以为您完成更多工作。相反,您可以将您的状态存储为从 std::tuple&lt;int, int&gt; 到浮动权重的 std::map。元组已经知道如何相互比较。这种思维方式将边缘的概念与重量的概念区分开来。

在不为您编写代码的情况下,这里展示了您正在寻找的那种能力……以“传统”C++ 方式完成:

#include <iostream>
#include <map>
#include <tuple>

typedef std::tuple<int, int> Edge;
std::map<Edge, float> mapEdgeToWeight;

int main() {
    Edge e1 {3, 5}; float w1 = 0.5;
    Edge e2 {3, 5}; float w2 = 0.5;

    auto it1 = mapEdgeToWeight.find(e1);
    if (it1 != mapEdgeToWeight.end())
        std::cout << "Existing {3, 5} edge (won't happen)\n";
    else {
        std::cout << "First {3, 5} edge (this is first)\n";
        mapEdgeToWeight[e1] = w1;
    }

    auto it2 = mapEdgeToWeight.find(e2);
    if (it2 != mapEdgeToWeight.end()) {
        std::cout << "Existing {3, 5} edge (now happens)\n";
        it2->second += w2; // first is edge, second is weight
    }
    else
        std::cout << "First {3, 5} edge (it isn't first!)\n";

    for (auto &pair : mapEdgeToWeight)
        std::cout << "Edge: "
            << std::get<0>(pair.first) << ","
            << std::get<1>(pair.first)
            << " Weight: " << pair.second << "\n";
}

正如 cmets 中所建议的,您最好考虑读取文件...处理它...然后写出一个新文件,而不是考虑在现有文件中“合并行”。

如果您是 C++ 新手,那么您需要学习大量内容,而来到 StackOverflow 时却不知道如何写东西并问“我该怎么做?”肯定会是一个艰难的方法。我建议通过阅读有关该主题的书籍来打下坚实的基础。即使您正在上课的课程有自己的课文,也不要害怕在这里选择一门好的现代课文来猜测它:

The Definitive C++ Book Guide and List

但是现在您至少知道一个可以开始的地方,通过查看有关如何使用 std::map 和 std::tuple 的教程。

【讨论】:

    猜你喜欢
    • 2013-05-28
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 2018-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多