QMap<QString, myStruct>如何排序?
How to sort QMap<QString, myStruct>?
我有一个 QMap<QString, myStruct>
和
myStruct {
QString firstname;
QString lastname;
QString status;
}
如何根据优先顺序对 QMap
进行排序:status
然后 firstname
然后 lastname
?
据我了解,您想检索以上述方式排序的地图值,但仍然可以访问键。对吗?
简而言之,地图是 <key, value>
对的集合,由 key 自动排序,那么您可以尝试手动排序的 <value, key>
对列表按 value 代替。类似于 QList<QPair<myStruct, QString>>
,同时覆盖 myStruct
.
的 operator<
struct myStruct {
QString firstname;
QString lastname;
QString status;
bool operator<(const myStruct& o) const {
return std::tie(status, firstname, lastname) <
std::tie(o.status, o.firstname, o.lastname);
}
};
QMap<QString, myStatus> map; // your original map
QList<QPair<myStatus, QString>> inv;
// Populate the inverted list
for (auto k : map.keys()) {
inv.append(QPair<myStatus, QString>(map[k], k));
}
std::sort(std::begin(inv), std::end(inv));
for (auto p : inv) {
qDebug() << p.first.status << p.first.firstname << p.first.lastname << p.second;
}
当然,它是一次性使用结构,不会与您的原始地图保持更新,但您提到该地图是固定(常量?)所以那么这可能不是问题。
顺便说一句,QMap
可用于反向查找,但仅在 myStruct
部分的值也是唯一的情况下(因此它们也可用作键), 否则在构建逆向映射时可能会覆盖值。
注意: std::tie
只是为了简化元组的排序条件(所以你需要包括 <tuple>
)。
更新
回答您的评论之一:是的,您也可以指定自己的比较谓词,然后避免重写 operator<
,但我认为它更难阅读且不易重用:
std::sort(std::begin(inv), std::end(inv),
[](const QPair<myStatus, QString>& lhs, const QPair<myStatus, QString>& rhs) {
return std::tie(lhs.first.status, lhs.first.firstname, lhs.first.lastname) <
std::tie(rhs.first.status, rhs.first.firstname, rhs.first.lastname);
});
当然,你可以根据需要实现比较lambda,我再次使用了std::tie
来简化post中的逻辑。不利的一面是,如果您需要在多个地方生成逆向映射,则必须在所有地方重复 lambda 表达式(当然也可以创建一个函数来创建逆向映射)。
作为旁注,以防万一您好奇,lhs
和 rhs
指的是 左侧 和 右侧-hand side 分别,在这种情况下,它们被排序算法用作 lhs < rhs
来比较元素。
最后,如果你想避免 std::tie
,你必须手动进行比较(下面的代码修改了第一个版本的 operator<
):
bool operator<(const myStruct& o) const {
if (status < o.status) return true;
if (status > o.status) return false;
// status == o.status, move to next attribute
if (firstname < o.firstname) return true;
if (firstname > o.firstname) return false;
// firstname== o.firstname, move to next attribute
if (lastname < o.lastname) return true;
if (lastname > o.lastname) return false;
return false; // are equal
}
您不能手动对 QMap
进行排序,您必须使用 QList
(或 QVector
)并在其上使用 std::sort
。使用 QMap::values()
将映射中的值(结构)提取到列表中,然后实现比较 function/method 并使用 std::sort
调用它。有关如何执行此操作的一些提示,请参阅 cbuchart 的回答。
当值发生变化时保持地图和列表同步是一个不同的问题,如果这是一个要求,您应该创建一个单独的问题,添加 MCVE 和更多关于您尝试过的细节。
我有一个 QMap<QString, myStruct>
和
myStruct {
QString firstname;
QString lastname;
QString status;
}
如何根据优先顺序对 QMap
进行排序:status
然后 firstname
然后 lastname
?
据我了解,您想检索以上述方式排序的地图值,但仍然可以访问键。对吗?
简而言之,地图是 <key, value>
对的集合,由 key 自动排序,那么您可以尝试手动排序的 <value, key>
对列表按 value 代替。类似于 QList<QPair<myStruct, QString>>
,同时覆盖 myStruct
.
operator<
struct myStruct {
QString firstname;
QString lastname;
QString status;
bool operator<(const myStruct& o) const {
return std::tie(status, firstname, lastname) <
std::tie(o.status, o.firstname, o.lastname);
}
};
QMap<QString, myStatus> map; // your original map
QList<QPair<myStatus, QString>> inv;
// Populate the inverted list
for (auto k : map.keys()) {
inv.append(QPair<myStatus, QString>(map[k], k));
}
std::sort(std::begin(inv), std::end(inv));
for (auto p : inv) {
qDebug() << p.first.status << p.first.firstname << p.first.lastname << p.second;
}
当然,它是一次性使用结构,不会与您的原始地图保持更新,但您提到该地图是固定(常量?)所以那么这可能不是问题。
顺便说一句,QMap
可用于反向查找,但仅在 myStruct
部分的值也是唯一的情况下(因此它们也可用作键), 否则在构建逆向映射时可能会覆盖值。
注意: std::tie
只是为了简化元组的排序条件(所以你需要包括 <tuple>
)。
更新
回答您的评论之一:是的,您也可以指定自己的比较谓词,然后避免重写 operator<
,但我认为它更难阅读且不易重用:
std::sort(std::begin(inv), std::end(inv),
[](const QPair<myStatus, QString>& lhs, const QPair<myStatus, QString>& rhs) {
return std::tie(lhs.first.status, lhs.first.firstname, lhs.first.lastname) <
std::tie(rhs.first.status, rhs.first.firstname, rhs.first.lastname);
});
当然,你可以根据需要实现比较lambda,我再次使用了std::tie
来简化post中的逻辑。不利的一面是,如果您需要在多个地方生成逆向映射,则必须在所有地方重复 lambda 表达式(当然也可以创建一个函数来创建逆向映射)。
作为旁注,以防万一您好奇,lhs
和 rhs
指的是 左侧 和 右侧-hand side 分别,在这种情况下,它们被排序算法用作 lhs < rhs
来比较元素。
最后,如果你想避免 std::tie
,你必须手动进行比较(下面的代码修改了第一个版本的 operator<
):
bool operator<(const myStruct& o) const {
if (status < o.status) return true;
if (status > o.status) return false;
// status == o.status, move to next attribute
if (firstname < o.firstname) return true;
if (firstname > o.firstname) return false;
// firstname== o.firstname, move to next attribute
if (lastname < o.lastname) return true;
if (lastname > o.lastname) return false;
return false; // are equal
}
您不能手动对 QMap
进行排序,您必须使用 QList
(或 QVector
)并在其上使用 std::sort
。使用 QMap::values()
将映射中的值(结构)提取到列表中,然后实现比较 function/method 并使用 std::sort
调用它。有关如何执行此操作的一些提示,请参阅 cbuchart 的回答。
当值发生变化时保持地图和列表同步是一个不同的问题,如果这是一个要求,您应该创建一个单独的问题,添加 MCVE 和更多关于您尝试过的细节。