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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

5回答

3665閲覧

文字列を降順の数値に変換する関数

stakezaki

総合スコア46

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2018/11/29 08:56

編集2018/11/30 07:12

表題のような関数をjavaで作成したいと考えています。
文字列xに対して降順となる数値もしくは文字列aを返す関数です。
f(x) = a
ただし、文字列xがx2>x1(x2.compareTo(x1)>0)のとき、aは降順、つまり、a2<a1となる数値か、もしくは、a2.compareTo(a1)<0となるような文字列を求めたいです。

例えば、以下になるような数値もしくは文字列を返す関数です。
f("1") = 10 だとすると、f("2") = 9
f("a") = 5 だとすると、f("b") = 4

右辺は順序が降順になっていれば自由な値で構いません。

これは、入力値を関数内でソートするようなものではなく、関数は複数回呼ばれますが、その値が結果的に降順になるというものです。

例えば、xがlongの最大値よりも小さい数字の場合、関数は以下のように書けます。
java.lang.Long.MAX_VALUE-Long.parseLong(x)
これを、xが文字列の場合でも求めたいのです。

そもそもの要件として、昇順しかソートできないKVSで降順を実現するために、降順用に項目を1つ追加し、降順の値を格納してそれをKVSの機能で昇順ソートすることで降順を実現したいというものです。

ヒントをもらって実装してみましたがダメでした。

java

1import java.util.ArrayList; 2import java.util.Collections; 3import java.util.Comparator; 4import java.util.HashMap; 5import java.util.List; 6import java.util.Map; 7import java.util.Map.Entry; 8 9public class DescTest { 10 11 public static void main(String[] args) { 12// String[] src = {"a", "b", "A", "abc", "def", "ab", "abcd", "あいうえお", "かきくけこ"}; 13 String[] src = {"a", "b", "c", "d", "e", "f", "g", "h", "i"}; 14 Map<Integer,String> dist = new HashMap<Integer,String>(); 15 16 for(int i=0;i<src.length;i++) { 17 dist.put(i, DescTest.decKey(src[i])); 18// dist.put(i, src[i]); 19 } 20 21 List<Map.Entry<Integer,String>> entries = 22 new ArrayList<Map.Entry<Integer,String>>(dist.entrySet()); 23 Collections.sort(entries, new Comparator<Map.Entry<Integer,String>>() { 24 25 @Override 26 public int compare( 27 Entry<Integer,String> entry1, Entry<Integer,String> entry2) { 28 return (entry1.getValue()).compareTo(entry2.getValue()); 29 } 30 }); 31 32 for (Entry<Integer,String> s : entries) { 33 System.out.println("s.getKey() : " + s.getKey()); 34 System.out.println("s.getValue() : " + src[s.getKey()]); 35 } 36 } 37 38 public static String decKey(String s) { 39 char[] c = s.toCharArray(); 40 int v = c[0]; 41// System.out.print("c="+v+" "); 42 for(int i = 0; i < c.length; i++) { 43 c[i] = (char)(65535 - c[i]); 44 } 45 return c.toString(); 46 } 47 48}

結果(降順にならない)

s.getValue() : b s.getKey() : 4 s.getValue() : e s.getKey() : 8 s.getValue() : i s.getKey() : 6 s.getValue() : g s.getKey() : 0 s.getValue() : a s.getKey() : 7 s.getValue() : h s.getKey() : 3 s.getValue() : d s.getKey() : 2 s.getValue() : c s.getKey() : 5 s.getValue() : f

よろしくお願いします。

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

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

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

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

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

maisumakun

2018/11/29 09:02

使う文字列の範囲は決まっていますか?
stakezaki

2018/11/29 09:17

範囲を決めないと多分作れないと思うので、xの文字数の最大の長さは固定として構いません。
maisumakun

2018/11/29 10:42

返り値の型をlongまでで考えると、あらゆる文字列を処理して矛盾しないようにするには「4文字」以下しか処理できませんが、それで問題ないでしょうか。
stakezaki

2018/11/29 10:46

いえ、それでは困りますので、戻り値の型はStringを希望します。
maisumakun

2018/11/29 10:51 編集

では逆に、Comparableを返す、という形では対応できないでしょうか。
stakezaki

2018/11/29 10:52

Comparableが返ってきた場合に、どのように降順の値を求めればいいかわからないです(これまで入力された値をすべて入れて実行するのは不可能なので)
maisumakun

2018/11/29 10:55

そもそもの要件として、「得られた値をどのように使いたい」のかを聞き忘れていましたね。
stakezaki

2018/11/29 10:59

すみません、質問に追記いたしました。
stakezaki

2018/11/29 11:09

文字列を数値化して最大値から引き算すればいいような気はしていますが、どのように実装すればいいのか。。
stakezaki

2018/11/29 11:37

少しわかってきたので自己解決に書きました。実装方法はまだです。
guest

回答5

0

例えば、xがlongの最大値よりも小さい数字の場合、関数は以下のように書けます。

java.lang.Long.MAX_VALUE-Long.parseLong(x)
これを、xが文字列の場合でも求めたいのです。

ということであればUnicodeに変換すれば良いのではないでしょうか?

BMPの範囲内であれば4桁の16進数を用いてU+0000~U+FFFFで表せるので、FFFF-その文字のUnicodeで求められると思います。

例)文字がaの場合
文字「a」はUnicodeでは「U+0061」の為、FFFF-0061を計算する

尚、サロゲートペアを含めて考える必要がある場合には第16面の最大値であるU+10FFFFを用いれば良いかと思います。

文字列をUnicodeに変換するには以下のコードで可能です。

Java

1public static String toUnicode(String str) 2{ 3 StringBuilder sb = new StringBuilder(); 4 for (int i = 0; i < str.length(); i++) { 5 sb.append(String.format("\u%04X", Character.codePointAt(str, i))); 6 } 7 String unicode = sb.toString(); 8 return unicode; 9}

このメソッドに「a」を通すと、返り値は「\u0061」となるので、
あとは\uを除いた「0061」を取得し、16進数で計算する部分を加えればよいはずです。

投稿2018/11/30 14:42

Simb

総合スコア118

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

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

stakezaki

2018/12/01 07:17

おっしゃるように、サロゲートペアまで考慮するとこの方法になるかと思います。ありがとうございます。
guest

0

全部ひっくり返せばいいんでない?

java

1public static String decKey(String s) { 2 char[] c = s.toCharArray(); 3 for(int i = 0; i < c.length; i++) { 4 c[i] = (char)(65535 - c[i]); 5 } 6 return new String(c); 7}

ごめんなさい、肝心の返り値を書いていませんでした。なお、この方法だと「a」「ab」のような「一方が他方より長いだけ」の順番が逆にならないのでご注意を。

てっきりJavaでのソートができない、あるいは何か別の固有の機能でソートするのかと思っていましたが、Javaプログラム上での並び替えができるなら簡単に済みます。
(entry1とentry2が逆になっているのがポイント)

java

1 Collections.sort(entries, new Comparator<Map.Entry<Integer,String>>() { 2 3 @Override 4 public int compare( 5 Entry<Integer,String> entry1, Entry<Integer,String> entry2) { 6 return (entry2.getValue()).compareTo(entry1.getValue()); 7 } 8 }); 9

なお、Java8以降であればyukkuriさんの回答のようなstaticメソッドでのComparatorが使えて便利です。

投稿2018/11/29 13:28

編集2018/11/30 17:30
swordone

総合スコア20651

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

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

stakezaki

2018/11/29 14:12

もしかしたら最大桁数で合わせないといけないかもしれませんが、こちらでいけるかもしれません。参考にさせていただきます。
stakezaki

2018/11/30 07:13

やってみましたが降順にはなりませんでした。(質問文に試したコードを追加しています)
stakezaki

2018/12/01 01:57

質問文のコードは計算結果の検証のためにソートを使っておりますが、Javaプログラム上での並び替えはできません。
stakezaki

2018/12/01 07:16

最初に教えていただいたコードを少し修正したらできました。ありがとうございます。
guest

0

自己解決

以下で解決しました。(サロゲートペアはとりあえず無視しています)

java

1 public static String decKey(String s) { 2 char[] c = s.toCharArray(); 3 String result = ""; 4 for(int i = 0; i < c.length; i++) { 5 result += (char)(65535 - c[i]); 6 } 7 return result; 8 }

検証用プログラム

package jp.reflexworks.atom.test; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class DescTest { public static void main(String[] args) { String[] src = {"a", "b", "A", "abc", "def", "ab", "abcd", "あいうえお", "かきくけこ"}; // String[] src = {"a", "b", "c", "d", "e", "f", "g", "h", "i"}; Map<Integer,String> dist = new HashMap<Integer,String>(); for(int i=0;i<src.length;i++) { dist.put(i, DescTest.decKey(src[i])); } List<Map.Entry<Integer,String>> entries = new ArrayList<Map.Entry<Integer,String>>(dist.entrySet()); Collections.sort(entries, new Comparator<Map.Entry<Integer,String>>() { @Override public int compare( Entry<Integer,String> entry1, Entry<Integer,String> entry2) { return (entry1.getValue()).compareTo(entry2.getValue()); } }); for (Entry<Integer,String> s : entries) { System.out.println("s.getKey() : " + s.getKey()); System.out.println("s.getValue() : " + src[s.getKey()]); } } public static String decKey(String s) { char[] c = s.toCharArray(); String result = ""; for(int i = 0; i < c.length; i++) { result += (char)(65535 - c[i]); } return result; } }

実行結果

s.getKey() : 8 s.getValue() : かきくけこ s.getKey() : 7 s.getValue() : あいうえお s.getKey() : 4 s.getValue() : def s.getKey() : 1 s.getValue() : b s.getKey() : 0 s.getValue() : a s.getKey() : 5 s.getValue() : ab s.getKey() : 3 s.getValue() : abc s.getKey() : 6 s.getValue() : abcd s.getKey() : 2 s.getValue() : A

投稿2018/12/01 07:13

stakezaki

総合スコア46

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

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

0

自己解決とまではいきませんが、文字列の大小比較をもう少し詳しく調べてみる(チェリー本の補足として)をヒントに、文字列をbyte配列として計算すればよさそうというのがわかってきました。

例えば、最大3文字として、
入力値 : ABCのbyte配列 => [65, 66, 67] を最大値[FF,FF,FF]から引いたものを降順の値とすることで解決できそうです。

投稿2018/11/29 11:36

stakezaki

総合スコア46

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

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

0

こういう感じでしょうか。

Java

1import java.util.Arrays; 2import java.util.Comparator; 3 4// main関数省略 5 6Integer arrayup[] = {3, 2, 1, 5, 4}; // 昇順用 7Integer arraydown = arrayup; 8 9Arrays.sort(arrayup, Comparator.naturalOrder()); // 昇順になる 10 11Arrays.sort(arraydown, Comparator.reverseOrder()); // 降順になる 12 13int count = 0; // 使用する arrayup の位置 14System.out.println( "f(\"" + arrayup[ count ] + "\") = " + arraydown[ arrayup.length - count - 1 ] );

###コメントによる追記
あまりメモリを気にしないなら、

Java

1int c = 1; // 入力値 c番目 2int max = 400; // 最大値 // これと上はコマンドラインで持ってきて変換したと想定 3 4Integer arrayup = new Integer[ max ]; 5for( int l = 0; l < max - 1; l++ ){ 6 arrayup[ l ] = l; 7} 8 9// 降順にするなどは上の回答を参照してください。

(すいません。わたしには1 -> 400 みたいにする式が出てきませんでした。その式を使うと
もっと効率化できるはずです。)

質問の追記による追記

ここまで式が出ているのなら、文字列から変換すればいいのでは?

String atai = "21"; long l = Long.parceLong( atai );

質問者自身の回答を見させていただいて

例えば、最大3文字として、

入力値 : ABCのbyte配列 => [65, 66, 67] を最大値[FF,FF,FF]から引いたものを降順の値とすることで解決できそうです。

ということなので、このような感じでしょうか。

Java

1/** 2 * 降順にソートします。 3 * 4 * @param by 変換する Byte 配列(長さはどれでもいいはず) 5 * 6 * @return 変換後の Byte[ by.length ] 7 */ 8public Byte[] sort( Byte[] by ) 9{ 10 Byte base = by; // 念の為コピー 11 for( int l = 0; l < base.length; l++ ){ 12 base[ l ] = FF - base[ l ]; 13 } 14 return base; // もしかしたら変数自体変更で void でいける? 15}

蛇足:そろそろ長くなってきたから回答分けようかなぁ...

投稿2018/11/29 09:34

編集2018/12/01 00:52
yukkuri

総合スコア624

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

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

stakezaki

2018/11/29 09:46

説明不足ですみません。入力値の最大文字数は固定で構いませんが、入力値自体は固定ではなく、都度入力されると考えてください。関数内部にすべての入力値を保持することもできません。
yukkuri

2018/11/29 09:50 編集

コマンドライン変数を、Integer もしくは int に変換すればいいかと。あと、最大文字数は固定で入力値は可変だと、安全性に問題がある気がしますが、まあifでどうにかなるか。というもんなのでだいじょうぶでしたすいません。
yukkuri

2018/11/29 09:56

回答に追記しました。
stakezaki

2018/11/29 10:18

まだ意図が伝わっていない感じです。入力値を関数内でソートするようなものではなく、関数は複数回呼ばれますが、その値が結果的に降順になるというものです。
stakezaki

2018/11/29 10:22

質問欄に数値の場合の例を追記しました。
cateye

2018/11/29 10:26

>関数内部にすべての入力値を保持することもできません。・・・は、前回返した最大と最小は保持できると考えていいのですか?
stakezaki

2018/11/29 10:32

前回返した最大と最小も保持できないとお考えください。
yukkuri

2018/11/29 23:25

上のを見た限り、関数に保持できない->クラスには保持できる、ということになりますが、多分それもなしなんですよね?
cateye

2018/11/29 23:44 編集

比較対象がなくてどうやって大小を見つけるんでしょうか??;
stakezaki

2018/12/01 02:00

比較対象は入力の文字コードの値になります。相対的に大小を計算するには文字コードの値をひっくり返すしかないと思っています。
cateye

2018/12/01 02:56

ごめん、頭悪いので教えて欲しいんですが、前回の文字コードって保持できるんですか?
stakezaki

2018/12/01 06:18

保持はできないですね
yukkuri

2018/12/01 07:08

もうここに追記でいいや。 Stringならcharに変換できる(charAt())なので、FF-charAt()で解決できませんか? (私は頭悪いので100%は理解できてない)
stakezaki

2018/12/01 07:15

charはFFFFが最大なのでFFFF-charAt()で解決できます。解決したコードを記入しました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問