2016-10-12 6 views
0

私は何かが不足しているかもしれませんが、最近いくつかの条件に従って最後のシンボルを取得するタスクに出くわしました。たとえば、私は文字列:"this_is_separated_values_5"を持っています。今私は5Intとして抽出したいと思います。スカラーのtakeRightWhile()メソッド

注:_で区切られた部分の数は定義されていません。

文字列にtakeRightWhile(f: Char => Boolean)メソッドがある場合、それは簡単です:takeRightWhile(ch => ch != '_')。さらに、効率的である。直接的な実装では、実際には_という最後のインデックスを見つけて、このメソッドを使用すると部分的な文字列を取りますが、最初のステップが節約され、平均時間の複雑さが改善されます。

UPDATE:みんなあなたが実際に追加O(n)スペースを使用して、str.reverse.takeWhile(_!='_').reverseのすべてのバリエーションは非常に非効率的です。メソッドtakeRightWhileを効率的に実装したい場合は、右から順番に繰り返し、結果を文字列ビルダーに累積して結果を返すことができます。私は、この種の方法について質問しています。すでに実装されている実装ではなく、質問自体で拒否されています。

質問:この種のメソッドはスカラー標準ライブラリに存在しますか?いいえの場合は、最小限の行数で同じようにするために、標準ライブラリからのメソッドの組み合わせはありますか?

ありがとうございます。あなたはfoldRightを使用して、以下の式で右から左に行くことができ

str.reverse.takeWhile(_!='_').reverse 

更新

答えて

3

解決策に

ここ
str.toList.foldRight(List.empty[Char]) { 
    case (item, acc) => item::acc 
} 

あなたが状態を確認し、追加を停止する必要があります条件が満たされた後のアイテム。このためには、累積値にフラグを渡すことができます。

val (_, list) = str.toList.foldRight((false, List.empty[Char])) { 
    case (item, (false, list)) if item!='_' => (false, item::list) 
    case (_, (_,  list))    => (true, list) 
} 
val res = list.mkString.toInt 

次いでこの溶液を、二重反転とソリューション、さらには非効率的である:foldRightの

  1. 実装は、リストの逆の組み合わせを使用して

  2. をfoldLeft
  3. foldRightの実行を中断することはできませんので、条件が満たされた後にすべての項目をスキップするフラグが必要です

+0

お返事ありがとうございます。質問の更新をご覧ください。 – tkachuko

+0

私の更新を参照してください。これがあなたにいくつかのアイデアを与えることを願っています – Nyavro

+0

ありがとうございました。少なくとも新しい文字列を作成しないので、以前のソリューションよりも効率的です。テール再帰とStringBuilderを簡素化して時間の複雑さを改善することができます(つまりfoldRightを終了させる)? – tkachuko

-1

StringBuilderとlastIndexWhereを使用できます。

val str = "this_is_separated_values_5" 
val sb = new StringBuilder(str) 
val lastIdx = sb.lastIndexWhere(ch => ch != '_') 
val lastCh = str.charAt(lastIdx) 
+0

これはテストしましたか?最後の '_'の後に複数の文字があると動作しないので、OPは文字列の残りの部分を望んでいます。最後の文字ではなく、最後の文字を取得することになります。 StringBuilderの必要もなく、 'lastIndexWhere'はStringで動作します。 –

+0

@TheArchetypalPaul私は質問を誤解しました。私は 'StringBuilder'で' lastIndexWhere'を最初に見つけ、 'StringOps'をチェックしませんでした。それらを指摘してくれてありがとう。 – NaHeon

+0

OK。まだ動作しません:) –

0

私はこれでいいと思う:

val s = "string_with_following_number_42" 
s.split("_").reverse.head 
// res:String = 42 

これはナイーブ試みと最適化されるものではありません。それは、StringArrayStringに分割し、それを逆にして最初の要素を取ります。分割が行われた後に逆転が起こるため、文字の順序は正しいことに注意してください。

+0

答えをありがとう。しかし、スプリットは.reverse.take.reverseアプローチよりもさらに悪いです。 – tkachuko

+0

なぜですか?私が思ったように、スプリットとリバースは両方ともO(n)になるString全体を反復する必要があります。 –

+0

時間の複雑さから、あなたは正しいですが、スプリットとリバースの両方が追加のnスペースフットプリントになります – tkachuko

0

私が直面している問題については、正確にはわかりません。私の理解では、フォーマットxxx_xxx_xx_...._xxx_123の文字列が必要で、最後にIntという部分を抽出したいと考えています。

import scala.util.Try 

val yourStr = "xxx_xxx_xxx_xx...x_xxxxx_123" 

val yourInt = yourStr.split('_').last.toInt 

// But remember that the above is unsafe so you may want to take it as Option 

val yourIntOpt = Try(yourStr.split('_').last.toInt).toOption 

または...あなたの条件は、いくつかのブール条件がtrue残るまでright-suffixを収集することであると言うことができます。

import scala.util.Try 

val yourStr = "xxx_xxx_xxx_xx...x_xxxxx_123" 

val rightSuffix = yourStr.reverse.takeWhile(c => c != '_').reverse 

val yourInt = rightSuffix.toInt 

// but above is unsafe so 
val yourIntOpt = Try(righSuffix.toInt).toOption 

お客様の要件がこれと異なる場合は、コメントしてください。

+0

答えをありがとう。しかし、スプリットは.reverse.take.reverseアプローチよりも悪いです。しかし、試してみていただきありがとうございます。 – tkachuko

+0

実際にスプリットアプローチは、あなたの要件が特定のキャラクターに分割されている方が良いです。しかし、他のブール条件に基づいて接尾辞を収集する必要がある場合は、 'reverse.take.reverse'のようなものが必要です –

関連する問題