Reputation: 169
I am trying to generate 5 letters word from random letters. Everything works fine but when I click my button to generate words it takes near about 2 minutes to generate those words and for those 2 minutes my button remains tapped(In blue color), which doesn't look good. I thought to put processing ring but that also doesn't work. Below is some coding for my method
String finalWrd = searchWrd.toUpperCase();
String twoLetterString = "";
int wordLen = searchWrd.length();//searchWrd is a random letter entered by user
String[] array = finalWrd.split("");
for(int i =1; i<=wordLen; i++)
for(int j=1; j<=wordLen; j++)
for(int K=1; K<=wordLen; K++)
for(int l=1; l<=wordLen; l++){
for(int m=1; m<=wordLen; m++){
twoLetterString += array[i] + array[j]+ array[K]+ array[l] + array[m] +",";
}
}
String[] array2Letters = twoLetterString.split(",");
int a =array2Letters.length, b = dictLinesArray.length;
for(int i =0;i<a; i++)
{
for(int l=0;l<b;l++)
{
if(array2Letters[i].equals(dictLinesArray[l]))
{
dictString2Lettes += dictLinesArray[l] +"," ;
}
}
}
text = dictString2Lettes;
Please help me, I need it for my college project. Thanks in advance
Upvotes: 2
Views: 130
Reputation: 2260
I'll attempt to offer you a decent solution to improve the performance of your algorithm. Use @Seraphim 's (or similar) answers to improve your user friendliness.
Fix your dictionary data structure.
1) Make your dictionary a Map<String,ArrayList<String>>
.
2) Add words in your dictionary like such:
String[] oldDictionary = {"using","suing","apple","orange"};
HashMap<String, ArrayList<String>> map = new HashMap<>();
for (int i = 0; i < oldDictionary.length; i++) {
char[] sort = oldDictionary[i].toCharArray();
Arrays.sort(sort);
String alphabetical = new String(sort);
if (map.containsKey(alphabetical)) {
map.get(alphabetical).add(oldDictionary[i]);
} else {
ArrayList<String> tmp = new ArrayList<>();
tmp.add(oldDictionary[i]);
map.put(alphabetical, tmp);
}
}
You can now use this new and improved data structure to find words super easily.
String inputWord = "iusgn";
char[] sort = inputWord.toCharArray();
Arrays.sort(sort);
inputWord = new String(sort);
if (map.containsKey(inputWord)) {
StringBuilder sb = new StringBuilder();
for (String word : map.get(inputWord)) {
sb.append(word + ",");
}
sb.deleteCharAt(sb.length() - 1);
System.out.println(sb.toString());
} else {
System.out.println("Nothing found :(");
}
Upvotes: 2
Reputation: 19284
I guess what takes you the most time is the second loop (because dictLinesArray
is big)
Try to change dictLinesArray
to Set and use contains
. The dictLinesSet
initialization should be done only once (at some init function).
Set<String> dictLinesSet = new HashSet<String>(Arrays.asList(dictLinesArray));
for(int i =0;i<a; i++){
if (dictLinesSet.contains(array2Letters[i])){
dictString2Lettes += array2Letters[i] +"," ;
}
}
Upvotes: 0
Reputation: 1
Some thoughts, I hope they help.
In your construction you are actually doing some less-than-optimal data management. Since the strings are immutable, for each time you go through the inner most loop (which is wordLen^5 iterations) you are creating 6 total String objects (right of the = sign), and making a seventh (left of the = sign). Strings are immutable in Java, and memory is a bigger concern in mobile apps than in laptop/desktop development. So for a word length of 5 you are creating 21,875 Objects. For a wordLen of 8 you are creating 229,376 Objects, and it only gets worse.
Better is to use a StringBuilder and store the value after you're done:
You would also want to make the twoLetterString a string builder from the get go.
StringBuilder twoLetterStringBuilder = new StringBuilder();
//inside the loop
twoLetterStringBuilder.append(array[i]).append(array[j]). ... .append(",");
At the end, just use
twoLetterStringBuilder.toString().split(",");
AsyncTask will keep things from locking up, but this should help you be much more efficient with your creation of objects and overall processing time.
Is the reason for all of the for loops some necessity to have an array of all possible permutations? If not just use:
Random r = new Random();
int arrayIndex = r.nextInt(wordLen);
Upvotes: 0
Reputation: 12768
I'll not comment the inefficency of your algorithm (try to find something better! :)). I'll simply give a solution for the UI that looks freezed:
"my button remains tapped(In blue color), which doesn't look good"
When your computation need time to be done, you need something like AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Suppose you are in your activity named MyActivity:
public class MyActivity extends BaseActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
Button btn = (Button)findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//execute async task
new FindWordsTask().execute();
}
});
}
Than you set up you AsyncTask like that:
private class FindWordsTask extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = ProgressDialog.show(MyActivity.this,
"Title",
"Finding words...", true);
}
@Override
protected Void doInBackground(Void... params) {
//do the computation,
//use here your function
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
progressDialog.dismiss();
}
}
Upvotes: 1