Say I had the string "foo1bar2" and I wanted to replace to perform the following replacements in parallel with an expected output of "bar1foo2".
foo => bar
bar => foo
The string cannot be tokenized as the substrings might occur anywhere, any number of times.
A naive approach would to be to replace like this, however it would fail as the 2nd replacement would undo the first.
String output = input.replace("foo", "bar").replace("bar", "foo");
=> foo1foo2
or
String output = input.replace("bar", "foo").replace("foo", "bar");
=> bar1bar2
I'm not sure regex can help me here either? This isn't homework by the way, just geeky interest. I've tried googling this but unsure how to describe the problem.
Try first replacing "foo" with something else that won't occur anywhere else in the String. Then replace "bar" with "foo" then replace the temporary replacement from step 1 with "bar".
I actually like Code-Guru's answer better, but since you said it's just a curiosity, here's a recursive solution. The idea is to isolate just the piece of the string that you are replacing and recurse on the rest so we don't accidentally replace something that we already did. Now if two of your rules have a common prefix, you may have to do some ordering of your rules to get the desired results, but here goes:
public class ParallelReplace
{
public String replace(String s, Rule... rules)
{
return runRule(s, 0, rules);
}
private String runRule(String s, int curRule, Rule... rules)
{
if (curRule == rules.length)
{
return s;
}
else
{
Rule r = rules[curRule];
int index = s.indexOf(r.lhs);
if (index != -1)
{
return runRule(s.substring(0, index), curRule + 1, rules) + r.rhs
+ runRule(s.substring(index + r.rhs.length()), curRule + 1, rules);
}
else
{
return runRule(s, curRule + 1, rules);
}
}
}
public static class Rule
{
public String lhs;
public String rhs;
public Rule(String lhs, String rhs)
{
this.lhs = lhs;
this.rhs = rhs;
}
}
public static void main(String[] args)
{
String s = "foo1bar2";
ParallelReplace pr = new ParallelReplace();
System.out.println(pr.replace(s, new Rule("foo", "bar"), new Rule("bar", "foo")));
}
}
Related
I am trying to find out if there is the same number of occurrences "dog" and "cat" are in the given String.
It should return true if they are equal, or false otherwise. How can I find out this without while, for etc. loops?
This is my current process
class Main {
public static boolean catsDogs(String s) {
String cat = "cat";
String dog = "dog";
if (s.contains(cat) && s.contains(dog)) {
return true;
}
return false;
}
public static void main(String[] args) {
boolean r = catsDogs("catdog");
System.out.println(r); // => true
System.out.println(catsDogs("catcat")); // => false
System.out.println(catsDogs("1cat1cadodog")); // => true
}
}
With java9+ the regex matcher has a count method:
public static boolean catsDogs(String s) {
Pattern pCat = Pattern.compile("cat");
Pattern pDog = Pattern.compile("dog");
Matcher mCat = pCat.matcher(s);
Matcher mDog = pDog.matcher(s);
return (mCat.results().count() == mDog.results().count());
}
You can use the following example by replacing the string (in case you don't want the split to be placed) :
public static boolean catsDogs(String s) {
return count(s,"cat") == count(s,"dog");
}
public static int count(String s, String catOrDog) {
return (s.length() - s.replace(catOrDog, "").length()) / catOrDog.length();
}
public static void main(String[] args) {
boolean r = catsDogs("catdog");
System.out.println(r); // => true
System.out.println(catsDogs("catcat")); // => false
System.out.println(catsDogs("1cat1cadodog")); // => true
}
Here's a couple of single-line solutions based on Java 9 Matcher.result() which produces a stream of MatchResult corresponding to each matching subsequence in the given string.
We can also make this method more versatile by providing a pair of regular expressions as arguments instead of hard-coding them.
teeing() + summingInt()
We can turn the stream of MatchResesult into a stream of strings by generating matching groups. And collect the data using collector teeing() expecting as its arguments two downstream collectors and a function producing the result based on the values returned by each collector.
public static boolean hasSameFrequency(String str,
String regex1,
String regex2) {
return Pattern.compile(regex1 + "|" + regex2).matcher(str).results()
.map(MatchResult::group)
.collect(Collectors.teeing(
Collectors.summingInt(group -> group.matches(regex1) ? 1 : 0),
Collectors.summingInt(group -> group.matches(regex2) ? 1 : 0),
Objects::equals
));
}
collectingAndThen() + partitioningBy()
Similarly, we can use a combination of collectors collectingAndThen() and partitioningBy().
The downside of this approach in comparison to the one introduced above is that partitioningBy() materializes stream elements as the values of the map (meanwhile we're interested only their quantity), but it performs fewer comparisons.
public static boolean hasSameFrequency(String str,
String regex1,
String regex2) {
return Pattern.compile(regex1 + "|" + regex2).matcher(str).results()
.map(MatchResult::group)
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(group -> group.matches(regex1)),
map -> map.get(true).size() == map.get(false).size()
));
}
I am trying to write a recursive method in Java that accepts two strings and then goes ahead and removes the instances of the second string from the first string (one at a time).
ex. String 1 == Mississippi, String 2 iss
first recursion == Missippi
then the final result should return Mippi
public class RecursionEx {
public static void main(String[] args) {
String str1 = "Mississippi";
String str2 = "iss";
System.out.println(repString(str1, str2));
}
public static String repString(String string1, String string2) {
//base case
if(string1.length()== 0)
return "";
//recursive case
if (string1.substring(0, string2.length()) == string2)
return repString(string1.substring(string2.length()), string2);
else
return repString(string1.substring(1), string2);
}}
Like the comment suggests, you should use equals() when comparing strings in Java, but you can also simplify your life by using the contains and removeFirst method for strings to deal with this recursive task.
I added a print line to the recursive function to show it is removing one instance of string2 at a time from string1.
public class StringRecursion {
public static void main(String[] args) {
String str1 = "Mississippi";
String str2 = "iss";
System.out.println(repString(str1, str2));
}
public static String repString(String string1, String string2) {
if(string1.contains(string2)) {
string1 = string1.replaceFirst(string2, "");
System.out.println("The string is currently: "+ string1);
}
else {
return string1;
}
return repString(string1, string2);
}
}
Output:
The string is currently: Missippi
The string is currently: Mippi
Mippi
Important: One other thing to consider with such an approach is if you want the pattern "iss" formed by an intermediate removal to also be removed. For instance, if you have the word "iissss" and want to remove "iss" it would become "" after running this even though iss does not appear twice in the word initially.
If you want to have the behavior mimic replaceAll function, where we are looking to only get rid of the "iss" patterns in the very first word and not the ones that appear in intermediate steps, I believe the function:
public static String repString(String string1, String string2) {
if(string1.contains(string2)) {
Pattern pattern = Pattern.compile(string2);
long originalCounts = pattern.matcher(string1).results().count();
string1 = string1.replaceFirst(string2, "");
long newCounts = pattern.matcher(string1).results().count();
if(originalCounts == newCounts) {
Matcher matcher = pattern.matcher(string1);
matcher.find();
int startPosition = matcher.end();
//Skip the generated matching pattern that appears in-between.
return string1.substring(0, startPosition) + repString(string1.substring(startPosition), string2);
}
//System.out.println("The string is currently: "+ string1);
}
else {
return string1;
}
return repString(string1, string2);
}
will be sufficient instead.
I want to list all names that end with "Reda" and ignore case sensitivity, I have tried the condition in the toString method at the bottom, but it would not print any thing.
public class Customer {
public static void main(String[] args) throws IOException {
File a = new File("customer.txt");
FileWriter v = new FileWriter(a);
BufferedWriter b = new BufferedWriter(v);
PrintWriter p = new PrintWriter(b);
human Iman = new human("Iman", 5000);
human Nour = new human("Nour", 3500);
human Redah = new human("Redah", 0);
human iman = new human("iman", 200);
human MohamedREDA = new human("MohamedREDA", 3000);
human Mohamed_Redah = new human("Mohamed Redah", 2000);
human[] h = new human[6];
h[0] = Iman;
h[1] = Nour;
h[2] = Redah;
h[3] = iman;
h[4] = MohamedREDA;
h[5] = Mohamed_Redah;
p.println(Iman);
p.println(Nour);
p.println(Redah);
p.println(iman);
p.println(MohamedREDA);
p.println(Mohamed_Redah);
p.flush();
}
}
class human {
public String name;
public double balance;
public human(String n, double b) {
this.balance = b;
this.name = n;
}
#Override
public String toString() {
if (name.equalsIgnoreCase("Reda") && (name.equalsIgnoreCase("Reda"))) {
return name + " " + balance;
} else
return " ";
}
}
Please avoid putting condition in toString method. Remove the condition there
public String toString() {
return name + " " + balance;
}
and change your logic in Customer class
human[] h = new human[6];
h[0] = Iman;
h[1] = Nour;
h[2] = Redah;
h[3] = iman;
h[4] = MohamedREDA;
h[5] = Mohamed_Redah;
for (int i = 0; i < h.length; i++) {
if (h[i].name.toLowerCase().endsWith("reda")) { // condition here
p.println(h[i]);
}
}
And make use of loops do not duplicate the lines of code.Every where you are manually writing the lines.
Check Java String class and use required methods to add condition.
String redahname = ("Redah").toLowerCase(); //put your h[0] instead of ("Redah")
if(name.endsWith("redah")){ //IMPORTANT TO BE IN LOWER CASE, (it is case insenitive this way)
//your code here if it ends with redag
System.out.println(redahname);
} //if it does not end with "redah" it wont out print it!
You can use this, but can you please explain your question more? What exactly do you need?
try this
#Override
public String toString() {
if (name.toLowerCase().endsWith("reda"))) {
return name + " " + balance;
} else
return " ";
}
String.equals() is not what you want as you're looking for strings which ends with "Reda" instead of those equal to "Reda". Using String.match or String.endsWith together with String.toLowerCase will do this for you. The following is the example of String.match:
public class Reda {
public static void main(String[] args) {
String[] names = {"Iman", "MohamedREDA", "Mohamed Redah", "reda"};
for (String name : names) {
// the input to matches is a regular expression.
// . stands for any character, * stands for may repeating any times
// [Rr] stands for either R or r.
if (name.matches(".*[Rr][Ee][Dd][Aa]")) {
System.out.println(name);
}
}
}
}
and its output:
MohamedREDA
reda
and here is the solution using endsWith and toLowerCase:
public class Reda {
public static void main(String[] args) {
String[] names = {"Iman", "MohamedREDA", "Mohamed Redah", "reda"};
for (String name : names) {
if (name.toLowerCase().endsWith("reda")) {
System.out.println(name);
}
}
}
}
and its output:
MohamedREDA
reda
You shouldn't put such condition in toString() method cause, it's not properly put business application logic in this method.
toString() is the string representation of an object.
What you can do, is putting the condition before calling the toString() , or making a helper method for this.
private boolean endsWithIgnoringCase(String other){
return this.name.toLowerCase().endsWith(other.toLowerCase());
}
None of your humans are called, ignoring case, Reda, so your observation of no names printed is the manifestation of properly working logic.
Your condition is redundant: you perform the same test twice:
name.equalsIgnoreCase("Reda") && (name.equalsIgnoreCase("Reda"))
If you need to match only the string ending, you should employ a regular expression:
name.matches("(?i).*reda")
toString is a general-purpose method defined for all objects. Using it the way you do, baking in the business logic for just one special use case, cannot be correct. You must rewrite the code so that toString uniformly returns a string representation of the object.
How can I improve this?
The relationship is one to one and continuous on [-1,5] so i was thinking of using enum, but I'm not sure how to compare a string value to an enum value.
If there is any better way to do this, please suggest.
Thanks!
private int evaluateWord(String sval) {
if (sval.equals("program"))
return 1;
else if (sval.equals("begin"))
return 2;
else if (sval.equals("end"))
return 3;
else if (sval.equals("int"))
return 4;
else if (sval.equals("if"))
return 5;
else
System.exit(0);
Have you considered stuffing the mapping into a HashMap once, and then just querying the map?
For example, something like this:
private static final Map<String,Integer> m_map = new HashMap<String,Integer>();
static {
m_map.put( "program", 1 );
m_map.put( "begin", 2 );
m_map.put( "end", 3 );
m_map.put( "int", 4 );
m_map.put( "if", 5 );
}
private int evaluateWord(String sval) {
Integer value = m_map.get( sval );
if ( null != value ) {
return value;
}
else {
System.exit(0);
}
}
By the way, it looks as if you're writing a parser. It can be reasonable to write a parser by hand. Another option to consider, unless you have a good reason to write it by hand, is a parser generator like ANTLR.
Using an enumeration:
enum Word {
PROGRAM(1,"program"),
BEGIN(2,"begin"),
END(3,"end"),
INT(4,"int"),
IF(5,"if");
private final int value;
private final String representation;
Word(int value, String representation)
{
this.value = value;
this.representation = representation;
}
public int value()
{ return value; }
private static Map<String, Word> fromRep =
new HashMap<String, EnumExample2.Word>();
public static Word fromRepresentation(String rep) {
if (!validRep(rep)) {
throw new IllegalArgumentException("No rep: "+rep);
}
return fromRep.get(rep);
}
public static boolean validRep(String rep)
{ return fromRep.get(rep) != null; }
static {
for (Word word : Word.values()) {
fromRep.put(word.representation, word);
}
}
}
Then your logic is:
private int evaluateWord(String sval) {
if (!Word.validRep(sval)) {
System.exit(0);
}
return Word.fromRepresentation(sval).value();
}
A hashmap could work:
private static HashMap<String, Integer> lookup = new HashMap<String, Integer>();
static {
lookup.put("program", 1);
lookup.put("being", 2);
lookup.put("end", 3);
lookup.put("int", 4);
lookup.put("if", 5);
}
private int evaluateWord(String sval) {
if ( lookup.containsKey(sval) ) {
return lookup.get(sval);
}
System.exit(0);
}
This is what a map is for;
Create a HashMap, add key and values to the map like
wordMap.put("program", Integer.valueOf(1));
....
then, to get the value do
Integer val = wordMap.get(sval);
Honestly, I wouldn't worry about keeping something like this ultra efficient, but there is a change you could make. If the word you pass is the last word you check for then your program ends up performing all of the checks in your function. This shouldn't be a problem in this case, but generally you don't want to flood your program with if statements, especially if you have a lot of cases.
Use a hashtable and just insert pairs. This way, all of your evaluateWord calls will return in amortized constant time. :)
Good luck!
Why do you need a (very subjective) "cleaner" way?
You could get more efficiency from using a hash lookup but you'd want to be certain it's called quite a bit to make the extra coding effort worthwhile. If it's something that happens infrequently (and, by that, I mean something like less than once a second), it's not worth doing (YAGNI).
One thing you might want to do for better looking code (if that's important) is to ditch the else bits, they're totally unnecessary:
private int evaluateWord(String sval) {
if (sval.equals("program")) return 1;
if (sval.equals("begin")) return 2;
if (sval.equals("end")) return 3;
if (sval.equals("int")) return 4;
if (sval.equals("if")) return 5;
System.exit(0);
}
You could just use an array or hashmap to map the enum values to the string values.
Inspired by your enum comment, I present the following. It's a bit hackish, but:
enum Word
{
PROGRAM (1), BEGIN (2), END (3), INT (4), IF (5);
public int value;
public Word (int value)
{
this.value = value;
}
};
int evaluateWord (String word)
{
return Word.valueOf(word.toUpperCase( )).value;
}
I love Java enums because you can do things like this. This is especially useful if you later want to (for example) add a unique behaviour for each word, or to maintain a long list of words. Note though that it is case insensitive.
Or, alternately:
enum Word
{
PROGRAM, BEGIN, END, INT, IF;
};
int evaluateWord (String word)
{
return Word.valueOf(word.toUpperCase( )).ordinal( ) + 1;
}
Given the following string:
"foo bar-baz-zzz"
I want to split it at the characters " " and "-", preserving their value, but get all combinations of inputs.
i want to get a two-dimensional array containing
{{"foo", "bar", "baz", "zzz"}
,{"foo bar", "baz", "zzz"}
,{"foo", "bar-baz", "zzz"}
,{"foo bar-baz", "zzz"}
,{"foo", "bar", "baz-zzz"}
,{"foo bar", "baz-zzz"}
,{"foo", "bar-baz-zzz"}
,{"foo bar-baz-zzz"}}
Is there any built-in method in Java to split the string this way? Maybe in a library like Apache Commons? Or do I have to write a wall of for-loops?
Here is a recursive solution that works. I used a List<List<String>> rather than a 2-dimensional array to make things easier. The code is a bit ugly and could probably be tidied up a little.
Sample output:
$ java Main foo bar-baz-zzz
Processing: foo bar-baz-zzz
[foo, bar, baz, zzz]
[foo, bar, baz-zzz]
[foo, bar-baz, zzz]
[foo, bar-baz-zzz]
[foo bar, baz, zzz]
[foo bar, baz-zzz]
[foo bar-baz, zzz]
[foo bar-baz-zzz]
Code:
import java.util.*;
public class Main {
public static void main(String[] args) {
// First build a single string from the command line args.
StringBuilder sb = new StringBuilder();
Iterator<String> it = Arrays.asList(args).iterator();
while (it.hasNext()) {
sb.append(it.next());
if (it.hasNext()) {
sb.append(' ');
}
}
process(sb.toString());
}
protected static void process(String str) {
System.err.println("Processing: " + str);
List<List<String>> results = new LinkedList<List<String>>();
// Invoke the recursive method that does the magic.
process(str, 0, results, new LinkedList<String>(), new StringBuilder());
for (List<String> result : results) {
System.err.println(result);
}
}
protected static void process(String str, int pos, List<List<String>> resultsSoFar, List<String> currentResult, StringBuilder sb) {
if (pos == str.length()) {
// Base case: Reached end of string so add buffer contents to current result
// and add current result to resultsSoFar.
currentResult.add(sb.toString());
resultsSoFar.add(currentResult);
} else {
// Step case: Inspect character at pos and then make recursive call.
char c = str.charAt(pos);
if (c == ' ' || c == '-') {
// When we encounter a ' ' or '-' we recurse twice; once where we treat
// the character as a delimiter and once where we treat it as a 'normal'
// character.
List<String> copy = new LinkedList<String>(currentResult);
copy.add(sb.toString());
process(str, pos + 1, resultsSoFar, copy, new StringBuilder());
sb.append(c);
process(str, pos + 1, resultsSoFar, currentResult, sb);
} else {
sb.append(c);
process(str, pos + 1, resultsSoFar, currentResult, sb);
}
}
}
}
Here's a much shorter version, written in a recursive style. I apologize for only being able to write it in Python. I like how concise it is; surely someone here will be able to make a Java version.
def rec(h,t):
if len(t)<2: return [[h+t]]
if (t[0]!=' ' and t[0]!='-'): return rec(h+t[0], t[1:])
return rec(h+t[0], t[1:]) + [ [h]+x for x in rec('',t[1:])]
and the result:
>>> rec('',"foo bar-baz-zzz")
[['foo bar-baz-zzz'], ['foo bar-baz', 'zzz'], ['foo bar', 'baz-zzz'], ['foo bar'
, 'baz', 'zzz'], ['foo', 'bar-baz-zzz'], ['foo', 'bar-baz', 'zzz'], ['foo', 'bar
', 'baz-zzz'], ['foo', 'bar', 'baz', 'zzz']]
Here is a class that will lazily return lists of split values:
public class Split implements Iterator<List<String>> {
private Split kid; private final Pattern pattern;
private String subsequence; private final Matcher matcher;
private boolean done = false; private final String sequence;
public Split(Pattern pattern, String sequence) {
this.pattern = pattern; matcher = pattern.matcher(sequence);
this.sequence = sequence;
}
#Override public List<String> next() {
if (done) { throw new IllegalStateException(); }
while (true) {
if (kid == null) {
if (matcher.find()) {
subsequence = sequence.substring(matcher.end());
kid = new Split(pattern, sequence.substring(0, matcher.start()));
} else { break; }
} else {
if (kid.hasNext()) {
List<String> next = kid.next();
next.add(subsequence);
return next;
} else { kid = null; }
}
}
done = true;
List<String> list = new ArrayList<String>();
list.add(sequence);
return list;
}
#Override public boolean hasNext() { return !done; }
#Override public void remove() { throw new UnsupportedOperationException(); }
}
(Forgive the code formatting - it is to avoid nested scrollbars).
For the sample invocation:
Pattern pattern = Pattern.compile(" |-");
String str = "foo bar-baz-zzz";
Split split = new Split(pattern, str);
while (split.hasNext()) {
System.out.println(split.next());
}
...it will emit:
[foo, bar-baz-zzz]
[foo, bar, baz-zzz]
[foo bar, baz-zzz]
[foo, bar-baz, zzz]
[foo, bar, baz, zzz]
[foo bar, baz, zzz]
[foo bar-baz, zzz]
[foo bar-baz-zzz]
I imagine the implementation could be improved upon.
Why do you need that?
Notice that for a given string of N tokens you want to get an array of ca N*2^N strings. This (can) consume tons of memory if not done in a safe way...
I guess that probably you will need to iterate trough it all, right? If so than its better to create some class that will keep the original string and just give you different ways of splitting a row each time you ask it. This way you will save tons of memory and get better scalability.
There is no library method.
To accomplish that, you should tokenize the string (in your case using " -") by preserving the separators, and then you should think of separators as associated to binary flags and build all combination based on the value of the flags.
In your case, you have 3 separators: " ", "-" and "-", so you have 3 binary flags. You will end up with 2^3 = 8 values in the string.