質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

607閲覧

pair型のような自作struct型でfirst要素の昇順とsecond要素の昇順を使い分けたい

moko3

総合スコア3

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2023/03/07 10:08

編集2023/03/07 10:30

質問

(タイトルのとおりです)

pair型のようなstruct型(例えば今回だとint L, int R)を自作した時に
bool operator<()でソートする方法を定義しておく
① first要素を優先する昇順ソートを実装
② second要素を優先する昇順ソートを実装

①first昇順と②second昇順を必要時に使い分けたいのですが

Q1:①と②をstruct内でbool operatorで実装して使い分けることは可能でしょうか?
(Q2:もしその他の方法でもっと良い方法が何かあれば教えて頂きたいです)

質問した経緯や背景

目的は普段使うテンプレとして所持しておきたい
大抵はpair型でなんとかなることが多かったのですが
first,second,昇順,降順,添字を1文字にして簡潔にしたい
ことなどをまとめてテンプレにしておけたらいざ使う時に便利そうだなと思いました

※コードは随分前にネットで調べていいとこ取りしたような記憶があるのですがうろ覚えで
いざ使いたいと思ったらよく分からないので質問させていただきました

試したこと

①と②を単独で実装して片方づつコメントアウトすることで
片方だけの実装は出来ましたが
両立させて使い分ける方法が分かりませんでした

参考にしたコード

C++17

C++

1#include <bits/stdc++.h> 2 3using namespace std; 4 5// RHS とは? 6// right-hand-side 7 8struct P { 9 P(int _L, int _R) : L(_L), R(_R) {} 10 11 // // first優先ソート 12 // bool operator<(const P& rhs) const { 13 // // L の値を優先してソートする 14 // return L != rhs.L ? L < rhs.L : R < rhs.R; 15 // } 16 17 // secod優先ソート 18 bool operator<(const P& rhs) const { 19 // R の値を優先してソートする 20 return R != rhs.R ? R < rhs.R : L < rhs.L; 21 } 22 23 int L; 24 int R; 25}; 26 27void solve() { 28 vector<P> p; 29 30 // input 31 p.emplace_back(P(8, 2)); 32 p.emplace_back(P(9, 1)); 33 p.emplace_back(P(7, 3)); 34 p.emplace_back(P(5, 5)); 35 p.emplace_back(P(6, 4)); 36 37 sort(p.begin(), p.end(), [](P a, P b) { return a.R < b.R; }); 38 for (auto e : p) cout << e.L << " " << e.R << "\n"; 39} 40 41int main() { (solve()); } 42 43// output 44/*** 459 1 468 2 477 3 486 4 495 5 50***/

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんなんでいいのかしら

C++

1#include <utility> 2#include <algorithm> 3#include <vector> 4#include <iostream> 5 6struct P { 7 P(int _L, int _R) : L(_L), R(_R) {} 8 9 static bool first_order(const P& lhs, const P& rhs) { 10 return lhs.L != rhs.L ? lhs.L < rhs.L : lhs.R < rhs.R; 11 } 12 13 static bool second_order(const P& lhs, const P& rhs) { 14 return lhs.R != rhs.R ? lhs.R < rhs.R : lhs.L < rhs.L; 15 } 16 17 int L; 18 int R; 19}; 20 21void solve() { 22 using namespace std; 23 vector<P> p; 24 25 // input 26 p.emplace_back(P(8, 2)); 27 p.emplace_back(P(9, 1)); 28 p.emplace_back(P(7, 3)); 29 p.emplace_back(P(5, 5)); 30 p.emplace_back(P(6, 4)); 31 32 sort(p.begin(), p.end(), P::first_order); 33 for (auto e : p) cout << e.L << " " << e.R << "\n"; 34 cout << endl; 35 sort(p.begin(), p.end(), P::second_order); 36 for (auto e : p) cout << e.L << " " << e.R << "\n"; 37} 38 39int main() { (solve()); }

投稿2023/03/07 10:56

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moko3

2023/03/07 11:25

回答ありがとうございます。 operator<()が1つしか使えないからどうしたら良いかと思っていました。 compare関数をstruct内部に複数個用意するイメージと解釈しました。 (違ってたらすみません)
episteme

2023/03/07 11:48

> compare関数をstruct内部に複数個用意するイメージと解釈しました。 その通り。(structの外で定義しても問題はないけど)
moko3

2023/03/07 13:55

コメントありがとうございます。 おかげさまで4種類(first,second,昇順,降順)の各ソートが出来るpair型ぽいstructのテンプレが作れました。
guest

0

質問が C++17 を前提としているので少しトピックから外れた回答となりますが C++20 からプロジェクション (投射) という概念が導入されました。 また、ソート関数でプロジェクションが利用できるようになりました。

要するに「変換」に類する処理を統一的なインターフェイスで扱えるようにするというのがプロジェクションの考え方で、関数ポインタ、関数オブジェクト、メンバポインタがプロジェクションとして使えます。

昇順・降順をどうするかとどの要素を比較するかを分けて指示することが出来るので様々な状況に対応しやすいのが利点でしょう。

cpp

1#include <algorithm> 2#include <iostream> 3#include <ranges> 4#include <tuple> 5#include <vector> 6 7struct either { 8 either(int left, int right) : left(left), right(right) {} 9 std::tuple<int, int> to_tuple() { 10 return std::make_tuple(this->left, this->right); 11 } 12 std::tuple<int, int> to_tuple_reverse_order() { 13 return std::make_tuple(this->right, this->left); 14 } 15 int left; 16 int right; 17}; 18 19std::ostream& operator<<(std::ostream& os, either& obj) { 20 os << '(' << obj.left << ',' << obj.right << ')'; 21 return os; 22} 23 24int main() { 25 std::vector<either> p = {{8, 2}, 26 {9, 1}, 27 {7, 3}, 28 {5, 5}, 29 {6, 4}}; 30 31 // 右側要素だけを見て (左側要素を無視して) 昇順に並べる 32 // メンバポインタをプロジェクションとして渡している 33 std::ranges::sort(p, std::ranges::less(), &either::right); 34 for (auto e : p) std::cout << e << '\n'; 35 std::cout << std::endl; 36 37 // 右側要素を優先して降順に並べる 38 // メンバ関数ポインタをプロジェクションとして渡している 39 std::ranges::sort(p, std::ranges::greater(), &either::to_tuple_reverse_order); 40 for (auto e : p) std::cout << e << '\n'; 41}

ちなみにプロジェクションの概念は C++20 からのものですが関数ポインタ、関数オブジェクト、メンバポインタを統一的に扱う std::invoke は C++17 から有ります。


それと質問内で提示されているコードで気になった点として識別子の名前があります。 アンダースコアで始まってそれに大文字が続く名前は予約されています。 そのような名前を使った結果は未定義ですので避けるべきです。


比較演算子 (operator< など) や四則演算の演算子は非メンバ関数として定義するのが通例です。 標準ライブラリでもそうなっています。 メンバ関数として定義しても仕様に反するわけではありませんが左辺では暗黙の型変換が働かない (右辺では働く) という不格好なことになってしまうからです。

投稿2023/03/08 12:22

SaitoAtsushi

総合スコア5444

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moko3

2023/03/09 08:40

回答ありがとうございます。 C++20は近い将来使うことになると思いますので参考になります。 あと全体的にモダンなコードの書き方?も意識されてるように伺えるところも参考になります。 (開発環境でC++17とC++20を混在させると混乱しそうなので今はC++17のみにして学習しています)
moko3

2023/03/09 08:41

>>アンダースコアで始まってそれに大文字が続く名前は予約されています。 ご指摘ありがとうございます。 何かのコードを参考にした時から(多分そのコードでは_x,_yなどを使っていたはずです) 見様見真似で意味も理解せずに_X,_Yのように勝手に自分の書きやすい書き方をしていました。 今後は使わないように気をつけます。
moko3

2023/03/09 08:44

>>比較演算子 (operator< など) や四則演算の演算子は非メンバ関数として定義するのが通例です。 ご指摘ありがとうございます。 これもよく理解せずにネットで調べたコードをそのまま自分なりにアレンジして使ってましたが勉強になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問