Is there a quick way to select the longest of three strings (s1,s2,s3) using if/else method?
I'm using Java
I have tried using something like this
if (s1.length() > s2.length()) {
System.out.println(s1); ...
but did not get it right.
Don't try to program all possible combinations with an if-else construct, as the complexity will grow exponentially if you add more strings.
This solution works well for a small number of strings with a linear complexity:
string longest = s1;
if (s2.length() > longest.length()) {
longest = s2;
}
if (s3.length() > longest.length()) {
longest = s3;
}
System.out.println(longest);
For a lager number of strings, put them in collection and find the longest using a loop.
You can use if, else if, else in C# (if you aren't actually using Java which it looks like you are) to handle this.
string current = str;
if(str2.Length > current.Length)
{
current = str2;
}
if (str3.Length > current.Length)
{
current = str3;
}
Unless using if/else is a requirement of this code, using a collection and LINQ will be a cleaner option.
List<string> strList = new List<string>
{
"str",
"strLen",
"strLength"
};
// This aggregate will return the longest string in a list.
string longestStr = strList.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
string a = "123";
string b = "1322";
string c = "122332";
if (a.Length > b.Length && a.Length > c.Length)
{
Console.WriteLine(a);
}
else if (b.Length > c.Length)
{
Console.WriteLine(b);
}
else
{
Console.WriteLine(c);
}
}
if/then/else constructs Java is same as C#. you can use solutions above. LINQ is like Streams in Java. In Java you can code:
public static void main(String args[]) {
printtLongest ("VampireApi","C#-Api","Java Api");
}
public static void printtLongest(String ... strings){
java.util.Arrays
.stream(strings)
.sorted(java.util.Comparator.comparingInt(String::length).reversed())
.findFirst().ifPresent(System.out::println);
}
create an array and input a string into each part of the array(can do this through loop or manually add- String[] st= new st String[]; then you can: st[0]="aaa"; st[1]="eff"... after this you can use a loop which takes the current length of the string at the array[i] and use a variable max(which will start at 0) which keep the highest length using the Math.max() function.
if the length(which is an integer) is larger then max then you save the string in a string variable and the loop will go through every string In your array and will update the max if needed. after this you can either return or print the string which is the longest.
this is one of many ways. or you could do three if's to check. this method would work great with larger amount of strings.
Not using if-else as the OP asked, but a cleaner solution is this:
void longest(String a, String b, String c) {
String[] triplet = {a, b, c};
Arrays.sort(triplet, Comparator.comparingInt(String::length));
System.out.println(triplet[2]);
}
Related
This question already has answers here:
Using Regex to generate Strings rather than match them
(12 answers)
Closed 7 years ago.
I want to get a list of all possible values for a regular expression.
Input :
2W
9WW
7W0W3
where W can be any digit from 0 to 9. i.e. W = [0-9]
Output:
20,21,22,....29
900,901,...910,911,...999
70003,70013,70023,...71003,72003,...79093
What I did :
I'm using Java and decided to create an ArrayList of Integers.
I created a method ArrayList<Integer> getNumbers(String regex).
ArrayList<Integer> getNumbers(String regex){
ArrayList<Integer> fullList = new ArrayList<Integer>();
char[] cArray = regex.toCharArray(); //converted the string into a character array.
for(int i=1;i<cArray.length;i++) {
if(cArray[i] == 'W') {
for(int j=0;j<10;j++) {
//I'm not sure what goes here
fullList.add(the number with 'w' at this index replaced by 'j');
}
}
}
return fullList;
}
Is there any better way or library functions available to generate all such numbers?
How can I achieve this?
This is not quite a regex-based problem, but from an algorithmic perspective you can do the followings:
Count the number of W's in your string.
Based on the number of W's, create the product of range(0,9), for example if you have 2 W you need to create the products of two [0...9] lists that will be something like 0,0-0,1-0,2-...-9,9.
Loop over the combinations and replace them with a simple string formatting. For instance when you are iterating over a triple combination suppose with 3 variables i,j,k you want want to replace them in a string like 7W0W3W, you can do "7%d0%dW%d"%(i,j,k).
And if you are looking for a general regex to wrap all the cases you can use a regex like (w) (w in a capture group) then you need to first access to position of the match groups and replace them with combination items (i,j,k,..).
It's better to call the input string as "pattern", not "regular expression". Also it's probably better to create a "virtual" list which generates the strings on demand. Here's the sample implementation:
public static List<String> getNumbers(String pattern) {
final char[] chars = pattern.toCharArray();
int size = 1;
for(char ch : chars)
if(ch == 'W') {
if(size == 1_000_000_000)
throw new IllegalArgumentException("Too many 'W' to fit the list");
size*=10;
}
final int finalSize = size;
return new AbstractList<String>() {
#Override
public String get(int index) {
char[] res = chars.clone();
for(int i=res.length-1; i>=0; i--) {
if(res[i] == 'W') {
res[i] = (char) ('0'+(index % 10));
index/=10;
}
}
return new String(res);
}
#Override
public int size() {
return finalSize;
}
};
}
First we count the number of 'W' chars and calculate the target list size accordingly. Then we return an implementation of AbstractList which for given list index replaces the 'W' symbols with the remainders of index division by 10. This list does not take the memory, it generates the String only when you request it. If you want to get the hard-copy of such list, you can use new ArrayList<>(getNumbers(pattern)).
I have seen other questions like this, but couldn't adapt any of the information to my code. Either because it wasn't specific to my issue or I couldn't get my head around the answer. So, I am hoping to ask "how" with my specific code. Tell me if more is needed.
I have various files (all jpg's) with names with the format "20140214-ddEventBlahBlah02.jpg" and "20150302-ddPsBlagBlag2".
I have a custom comparator in use that sorts things in a Windows OS fashion... i.e. 02,2,003,4,4b,4c,10, etc. Instead of the computer way of sorting, which was screwed up. Everything is good, except I now want to sort these strings using 2 criteria in the strings.
1) The date (in the beginning). i.e. 20150302
2) The rest of the filename after the "-" i.e. ddPsBlagBlag2
I am currently using the comparator for a project that displays these files in reverse order. They are displaying according to what was added most recently. i.e. 20150302 is displaying before 20140214. Which is good. But I would like the files, after being sorted by date in reverse order, to display by name in normal Windows OS ascending order (not in reverse).
Code:
Collections.sort(file, new Comparator<File>()
{
private final Comparator<String> NATURAL_SORT = new WindowsExplorerComparator();
#Override
public int compare(File o1, File o2)
{
return NATURAL_SORT.compare(o1.getName(), o2.getName());
}
});
Collections.reverse(file);
The code above takes the ArayList of file names and sends it to the custom WindowsExplorerComparator class. After being sorted, Collections.reverse() is called on the ArrayList.
Code:
class WindowsExplorerComparator implements Comparator<String>
{
private static final Pattern splitPattern = Pattern.compile("\\d\\.|\\s");
#Override
public int compare(String str1, String str2) {
Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
while (true)
{
//Til here all is equal.
if (!i1.hasNext() && !i2.hasNext())
{
return 0;
}
//first has no more parts -> comes first
if (!i1.hasNext() && i2.hasNext())
{
return -1;
}
//first has more parts than i2 -> comes after
if (i1.hasNext() && !i2.hasNext())
{
return 1;
}
String data1 = i1.next();
String data2 = i2.next();
int result;
try
{
//If both datas are numbers, then compare numbers
result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
//If numbers are equal than longer comes first
if (result == 0)
{
result = -Integer.compare(data1.length(), data2.length());
}
}
catch (NumberFormatException ex)
{
//compare text case insensitive
result = data1.compareToIgnoreCase(data2);
}
if (result != 0) {
return result;
}
}
}
private List<String> splitStringPreserveDelimiter(String str) {
Matcher matcher = splitPattern.matcher(str);
List<String> list = new ArrayList<String>();
int pos = 0;
while (matcher.find()) {
list.add(str.substring(pos, matcher.start()));
list.add(matcher.group());
pos = matcher.end();
}
list.add(str.substring(pos));
return list;
}
}
The code above is the custom WindowsExplorerComperator class being used to sort the ArrayList.
So, an example of what I would like the ArrayList to look like after being sorted (and date sort reversed) is:
20150424-ssEventBlagV002.jpg
20150323-ssEventBlagV2.jpg
20150323-ssEventBlagV3.jpg
20150323-ssEventBlagV10.jpg
20141201-ssEventZoolander.jpg
20141102-ssEventApple1.jpg
As you can see, first sorted by date (and reversed), then sorted in ascending order by the rest of the string name.
Is this possible? Please tell me its an easy fix.
Your close, whenever dealing with something not working debug your program and make sure that methods are returning what you would expect. When I ran your program first thing I noticed was that EVERY compare iteration which attempted to convert a string to Long threw a NumberFormatException. This was a big red flag so I threw in some printlns to check what the value of data1 and data2 were.
Heres my output:
Compare: 20150323-ssEventBlagV 20150424-ssEventBlagV00
Compare: 20150323-ssEventBlagV 20150323-ssEventBlagV
Compare: 3. 2.
Compare: 20150323-ssEventBlagV 20150424-ssEventBlagV00
Compare: 20150323-ssEventBlagV 20150323-ssEventBlagV
Compare: 3. 2.
Compare: 20150323-ssEventBlagV1 20150323-ssEventBlagV
Compare: 20150323-ssEventBlagV1 20150424-ssEventBlagV00
Compare: 20141201-ssEventZoolander.jpg 20150323-ssEventBlagV1
Compare: 20141201-ssEventZoolander.jpg 20150323-ssEventBlagV
Compare: 20141201-ssEventZoolander.jpg 20150323-ssEventBlagV
Big thing to notice here is that its trying to convert 3. and 2. to long values which of course wont work.
The simplest solution with your code is to simply change your regular expression. Although you might go for a more simple route of string iteration instead of regex in the future, I feel as though regex complicates this problem more than it helps.
New regex: \\d+(?=\\.)|\\s
Changes:
\\d -> \\d+ - Capture all digits before the period not just the first one
\\. -> (?=\\.) - place period in non capturing group so your method doesn't append it to our digits
New debug output:
Compare: 20150323-ssEventBlagV 20150424-ssEventBlagV
Compare: 20150323-ssEventBlagV 20150323-ssEventBlagV
Compare: 3 2
Compare: 20150323-ssEventBlagV 20150323-ssEventBlagV
Compare: 10 3
Compare: 20141201-ssEventZoolander.jpg 20150323-ssEventBlagV
As you can see the numbers at the end are actually getting parsed correctly.
One more minor thing:
Your result for digit comparison is backwards
result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
should be either:
result = -Long.compare(Long.valueOf(data1), Long.valueOf(data2));
or
result = Long.compare(Long.valueOf(data2), Long.valueOf(data1));
because its sorting them backwards.
There are a few things you should do:
First, you need to fix your split expression as #ug_ stated. However, I think splitting on numbers is more appropriate.
private static final Pattern splitPattern = Pattern.compile("\\d+");
which, for 20150323-ssEventBlagV2.jpg will result in
[, 20150323, -ssEventBlagV, 2, .jpg]
Second, perform a date comparison separate from your Long comparison. Using SimpleDateFormat will make sure you are only comparing numbers that are formatted as dates.
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
result = sdf.parse(data2).compareTo(sdf.parse(data1));
if (result != 0) {
return result;
}
} catch (final ParseException e) {
/* continue */
}
Last, swap the order of your Long compare
Long.compare(Long.valueOf(data2), Long.valueOf(data1));
And you should be good to go. Full code below.
private static final Pattern splitPattern = Pattern.compile("\\d+");
#Override
public int compare(String str1, String str2) {
Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
while (true) {
// Til here all is equal.
if (!i1.hasNext() && !i2.hasNext()) {
return 0;
}
// first has no more parts -> comes first
if (!i1.hasNext() && i2.hasNext()) {
return -1;
}
// first has more parts than i2 -> comes after
if (i1.hasNext() && !i2.hasNext()) {
return 1;
}
String data1 = i1.next();
String data2 = i2.next();
int result;
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
result = sdf.parse(data1).compareTo(sdf.parse(data2));
if (result != 0) {
return result;
}
} catch (final ParseException e) {
/* continue */
}
try {
// If both datas are numbers, then compare numbers
result = Long.compare(Long.valueOf(data2),
Long.valueOf(data1));
// If numbers are equal than longer comes first
if (result == 0) {
result = -Integer.compare(data1.length(),
data2.length());
}
} catch (NumberFormatException ex) {
// compare text case insensitive
result = data1.compareToIgnoreCase(data2);
}
if (result != 0) {
return result;
}
}
}
You will need to edit your WindowsExporerComparator Class so that it performs this sorting. Given two file names as Strings you need to determine what order they go in using a following high level algorithm.
are they the same? if yes return 0
Split the file name into two strings, the date portion and the name portion.
Using the date portion convert the string to a date using the Java DateTime and then compare the dates.
If the dates are the same compare the two name portions using your current compare code and return the result from that.
This is a bit complicated and sort of confusing, but you will have to do it in one comparator and put in all of your custom logic
I have a string: LOAN,NEFT,TRAN. I want to substring the string based on getting a , during traversing the string. So I tried to first get a count for how many , are there. but not sure what function to user to get what I want. Also this should be dynamic, meaning I should be able to create as many substrings as required based on number of ,s. I tried the following code:
package try1;
public class StringTest {
public static void main(String[] args) {
String str="LOAN,NEFT,TRAN";
int strlen=str.length();
int count=0;
for(int i=0;i<strlen;i++)
{
if(str.contains("'"))
count++;
}
System.out.println(""+count);
for (int j=0;j<count;j++)
{
//code to create multiple substrings out of str
}
}
}
But I do not think contains() is the function I am looking for because value of count here is coming 0. What should I use?
Your code doesn't actually count the , characters because 1) contains doesn't take into account your loop variable 2) it's searching for ', not ,
Assuming you want to work at a low level rather than using high level functions like .split(), then I'd recommend the following.
for(char c : str.toCharArray()) {
if (c == ',') {
count++;
}
}
You can use split to get substrings directly:
String[] substrings = str.split(",");
Is this what you want as an output: (shown below)?
["LOAN", "NEFT", "TRAN"] // Array as an output
Or to just get the count of the splitting char, you can use the same line as above with this:
int count = substrings.length - 1;
I have 2 strings "test" "bet" and another string a="tbtetse". I need to check if the "tbtetse" contains the other two strings.
I was thinking if I could find all the anagrams of string a and and then find the other two strings in those, but it doesn't work that way and also my anagram code is failing for a lengthy string.
Could you please help with any other ways to solve it?
Assuming you're trying to test whether the letters in a can be used to form an anagram of the test strings test and bet: I recommend making a dictionary (HashMap or whatever) of character counts from string a, indexed by character. Build a similar dictionary for the words you're testing. Then make sure that a has at least as many instances of each character from the test strings as they have.
Edit: Alcanzar suggests arrays of length 26 for holding the counts (one slot for each letter). Assuming you're dealing with only English letters, that is probably less of a hassle than dictionaries. If you don't know the number of allowed characters, the dictionary route is necessary.
Check below code, it may help you.
public class StringTest {
public static void main(String[] args) {
String str1 = "test";
String str2 = "bev";
String str3 = "tbtetse";
System.out.println(isStringPresent(str1, str2, str3));
}
private static boolean isStringPresent(String str1, String str2, String str3) {
if ((str1.length() + str2.length()) != str3.length()) {
return false;
} else {
String[] str1Arr = str1.split("");
String[] str2Arr = str2.split("");
for (String string : str1Arr) {
if (!str3.contains(string)) {
return false;
}
}
for (String string : str2Arr) {
if (!str3.contains(string)) {
return false;
}
}
}
return true;
}
}
basically you need to count characters in both sets and compare them
void fillInCharCounts(String word,int[] counts) {
for (int i = 0; i<word.length(); i++) {
char ch = word.charAt(i);
int index = ch - 'a';
counts[index]++;
}
}
int[] counts1 = new int[26];
int[] counts2 = new int[26];
fillInCharCounts("test",counts1);
fillInCharCounts("bet",counts1);
fillInCharCounts("tbtese",counts2);
boolean failed = false;
for (int i = 0; i<counts1.length; i++) {
if (counts1[i] > counts2[i]) {
failed = true;
}
}
if (failed) {
whatever
} else {
something else
}
If you are generalizing it, don't forget to call .toLowerCase() on the word before sending it in (or fix the counting method).
Pseudo code:
Make a copy of string "tbtetse".
Loop through each character in "test".
Do a indexOf() search for the character in your copied string and remove it if found.
If not found, fail.
Do the same for the string "bet".
class WordLetter {
char letter;
int nth; // Occurrence of that letter
...
}
One now can use Sets
Set<WordLetter>
// "test" = { t0 e0 s0 t1 }
Then testing reduces to set operations. If both words need to be present, a union can be tested. If both words must be formed from separate letters, a set of the concatenation can be tested.
For a school project I was asked to write a simple math parser in Java. The program works fine. So fine that I used NetBeans profiler tool to check the performance of the program. For that I made a loop of 1000 calls to the math parser of the following expression: "1-((x+1)+1)*2", where x was replaced by the current loop count. It took 262ms. The thing is, it took 50% of the time in the method splitFormula, which I shall present below:
private static void splitFormula(String formula){
partialFormula=new ArrayList<>();
for(String temp: formula.split("\\+|\\-|\\*|\\/"))
partialFormula.add(temp);
}
, where partialFormula is an ArrayList of Strings. To numerically evaluate an expression I need to call the splitFormula method various times so I really need to clear the contents of the partialFormula ArrayList - first line.
My question is: is there a faster way to split a string then add the partial strings to the an arraylist? Or is there some other method that can be used to split a string then use the substrings?
Regular expressions can slow things down (String#split uses regex). In general, if you want to write easy code, regex is good, but if you want fast code, see if there is another way. Try doing this without regex:
Edit: This should be a better method (keep track of the indices instead of append to a StringBuilder):
private static void splitFormula(String formula){
partialFormula.clear(); // since there is a method for this, why not use it?
int lastIndex = 0;
for (int index = 0; index < formula.length(); index++) {
char c = formula.charAt(index);
if (c == '-' || c == '+' || c == '*' || c == '/') {
partialFormula.add(formula.substring(lastIndex, index));
lastIndex = index + 1; //because if it were index, it would include the operator
}
}
partialFormula.add(formula.substring(lastIndex));
}
StringBuilder approach:
private static void splitFormula(String formula){
partialFormula.clear();
StringBuilder newStr = new StringBuilder();
for (int index = 0; index < formula.length(); index++) {
char c = formula.charAt(index);
if (c == '-' || c == '+' || c == '*' || c == '/') {
partialFormula.add(newStr.toString());
newStr.setLength(0);
} else {
newStr.append(c);
}
}
partialFormula.add(newStr.toString());
}
If we look at the source code for String#split, it becomes apparent why that is slower (from GrepCode):
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
It compiles a regex every time! Thus, we can see that another way of speeding up the code is to compile our regex first, then use the Pattern#split to split:
//In constructor, or as a static variable.
//This regex is a better form of yours.
Pattern operatorPattern = Pattern.compile("[-*+/]");
...
private static void splitFormula(String formula){
partialFormula.clear();
for(String temp: operatorPattern.split(formula)) {
partialFormula.add(temp);
}
}
You don't need a for loop. split returns an array, and you can create an ArrayList out of the array:
partialFormula = new ArrayList<>(Arrays.asList(formula.split("\\+|\\-|\\*|\\/")));
Whether this is significantly faster or not, I don't know.
Try pre-allocating the ArrayList beforehand so we do not have to pay for reallocation when the list grows. The number 20 below is just a placeholder. Pick a number that is a little bigger than the largest expression you expect.
partialFormula=new ArrayList<String>(20);
See this question for a discussion of what this might gain you.
This will create an arrayList of strings.
String a= "1234+af/d53";
char [] blah=a.toCharArray();
ArrayList<String> list=new ArrayList<String>();
for (int i = 0; i < blah.length; i++) {
list.add(Character.toString(blah[i]));
}