Given a word, how do I find other words in an array with same length and same characters
$begingroup$
I tried solving the problem in the following manner; I am just a beginner and wanted to know my mistakes and a more efficient way with better time complexity (if any).
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
java
New contributor
$endgroup$
|
show 1 more comment
$begingroup$
I tried solving the problem in the following manner; I am just a beginner and wanted to know my mistakes and a more efficient way with better time complexity (if any).
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
java
New contributor
$endgroup$
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago
|
show 1 more comment
$begingroup$
I tried solving the problem in the following manner; I am just a beginner and wanted to know my mistakes and a more efficient way with better time complexity (if any).
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
java
New contributor
$endgroup$
I tried solving the problem in the following manner; I am just a beginner and wanted to know my mistakes and a more efficient way with better time complexity (if any).
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
java
java
New contributor
New contributor
edited 11 hours ago
Aditya
New contributor
asked 16 hours ago
AdityaAditya
62
62
New contributor
New contributor
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago
|
show 1 more comment
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago
|
show 1 more comment
2 Answers
2
active
oldest
votes
$begingroup$
Whitespace is very important for readability. For posting to Stack Exchange sites I recommend replacing tabs with spaces, because otherwise the site does that for you and the tabstops might not match. Here, though, the whitespace is so crazy that I think you need to look at configuring your IDE to pretty-print the code. Reformatting so that I can understand the structure:
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
Names
Java convention is that camel-case names which start with a capital letter are types (classes, interfaces, etc), so Search
as the name of a variable is unexpected.
counter
is not entirely uninformative, but a better name would tell me what it counts. Similarly, it would be helpful to distinguish which variables relate to the search query and which to the items searched. The best convention I've seen there is PHP's needle
and haystack
, so I would suggest needleLetters
and haystackWords
.
foreach statement
Instead of for(int i=0;i<words.length;i++) ... words[i]
you can use for (String word : words) ... word
. This removes a variable and simplifies the naming, making it easier to see what the code does.
Decomposing strings
String
has a method toCharArray()
. I think it would make more sense to use that than split("")
.
Don't put something in a loop which can go outside it
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
...
}
}
could be rewritten
if(letters.length==ssplit.length)
{
for(int j=0;j<ssplit.length;j++)
{
...
}
}
Executing the test once is more efficient, and it's also easier to understand because the maintainer doesn't have to reason about loop invariants to work out what might have changed the second time the test is executed.
Since there's nothing after this test in the loop body, an alternative would be
if(letters.length!=ssplit.length)
{
continue;
}
for(int j=0;j<ssplit.length;j++)
{
...
}
Beware hard-coded constants
Why
if (counter == 4)
{
System.out.println(words[i]);
}
? That's a bug. The comparison should be with letters.length
. Also, it would make more sense to move the test outside the loop over j
.
Use advanced data structures
for(int j=0;j<words[i].length();j++)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
}
takes time proportional to words[i].length() * letters.length
. If you use java.util.HashMap<Character, Integer>
to store a per-character count, you can generate a representation for each word in time proportional to the length of the word, and you can compare the representations of two words in time proportional to the length of each word. In this toy example it doesn't matter, but for real applications the difference between $O(n^2)$ and $O(n)$ can be the difference between a project being feasible and not. The first place to look for optimisations is always the algorithm.
$endgroup$
add a comment |
$begingroup$
welcome on Codereview.
I am pretty sure that you will find many other ways to do it the comments from @NateGardner is already a good suggestion. But the goal is to review your code so I will just try to suggest some improvements to your code.
First of all I will just reformat the code, create a dedicated class for it and define the input and output.
class WordFinder {
private final String words;
WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
String find(String word) {
// Your code here
}
}
Then you can start to split your nested logic in different methods and use exiting methods to simplify your code (like String#toCharArray()
instead of String#split("")
)
String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( this.matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
As said in the beginning, there is a lot of way to test two words for matching and I am sure that you will find the best one. For this answer, I decided to compare the hash of each array of char
.
Here is my code if you want. But if you can use other structure from the collections or the stream API, this one can be totally different.
public class WordFinder {
private final String words;
public WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
public String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
private boolean matches(char requirement, char candidate) {
return candidate.length==requirement.length &&
hash(candidate)==hash(requirement);
}
private int hash(char array) {
char copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy);
return Arrays.hashCode(copy);
}
}
$endgroup$
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Aditya is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211538%2fgiven-a-word-how-do-i-find-other-words-in-an-array-with-same-length-and-same-ch%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Whitespace is very important for readability. For posting to Stack Exchange sites I recommend replacing tabs with spaces, because otherwise the site does that for you and the tabstops might not match. Here, though, the whitespace is so crazy that I think you need to look at configuring your IDE to pretty-print the code. Reformatting so that I can understand the structure:
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
Names
Java convention is that camel-case names which start with a capital letter are types (classes, interfaces, etc), so Search
as the name of a variable is unexpected.
counter
is not entirely uninformative, but a better name would tell me what it counts. Similarly, it would be helpful to distinguish which variables relate to the search query and which to the items searched. The best convention I've seen there is PHP's needle
and haystack
, so I would suggest needleLetters
and haystackWords
.
foreach statement
Instead of for(int i=0;i<words.length;i++) ... words[i]
you can use for (String word : words) ... word
. This removes a variable and simplifies the naming, making it easier to see what the code does.
Decomposing strings
String
has a method toCharArray()
. I think it would make more sense to use that than split("")
.
Don't put something in a loop which can go outside it
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
...
}
}
could be rewritten
if(letters.length==ssplit.length)
{
for(int j=0;j<ssplit.length;j++)
{
...
}
}
Executing the test once is more efficient, and it's also easier to understand because the maintainer doesn't have to reason about loop invariants to work out what might have changed the second time the test is executed.
Since there's nothing after this test in the loop body, an alternative would be
if(letters.length!=ssplit.length)
{
continue;
}
for(int j=0;j<ssplit.length;j++)
{
...
}
Beware hard-coded constants
Why
if (counter == 4)
{
System.out.println(words[i]);
}
? That's a bug. The comparison should be with letters.length
. Also, it would make more sense to move the test outside the loop over j
.
Use advanced data structures
for(int j=0;j<words[i].length();j++)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
}
takes time proportional to words[i].length() * letters.length
. If you use java.util.HashMap<Character, Integer>
to store a per-character count, you can generate a representation for each word in time proportional to the length of the word, and you can compare the representations of two words in time proportional to the length of each word. In this toy example it doesn't matter, but for real applications the difference between $O(n^2)$ and $O(n)$ can be the difference between a project being feasible and not. The first place to look for optimisations is always the algorithm.
$endgroup$
add a comment |
$begingroup$
Whitespace is very important for readability. For posting to Stack Exchange sites I recommend replacing tabs with spaces, because otherwise the site does that for you and the tabstops might not match. Here, though, the whitespace is so crazy that I think you need to look at configuring your IDE to pretty-print the code. Reformatting so that I can understand the structure:
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
Names
Java convention is that camel-case names which start with a capital letter are types (classes, interfaces, etc), so Search
as the name of a variable is unexpected.
counter
is not entirely uninformative, but a better name would tell me what it counts. Similarly, it would be helpful to distinguish which variables relate to the search query and which to the items searched. The best convention I've seen there is PHP's needle
and haystack
, so I would suggest needleLetters
and haystackWords
.
foreach statement
Instead of for(int i=0;i<words.length;i++) ... words[i]
you can use for (String word : words) ... word
. This removes a variable and simplifies the naming, making it easier to see what the code does.
Decomposing strings
String
has a method toCharArray()
. I think it would make more sense to use that than split("")
.
Don't put something in a loop which can go outside it
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
...
}
}
could be rewritten
if(letters.length==ssplit.length)
{
for(int j=0;j<ssplit.length;j++)
{
...
}
}
Executing the test once is more efficient, and it's also easier to understand because the maintainer doesn't have to reason about loop invariants to work out what might have changed the second time the test is executed.
Since there's nothing after this test in the loop body, an alternative would be
if(letters.length!=ssplit.length)
{
continue;
}
for(int j=0;j<ssplit.length;j++)
{
...
}
Beware hard-coded constants
Why
if (counter == 4)
{
System.out.println(words[i]);
}
? That's a bug. The comparison should be with letters.length
. Also, it would make more sense to move the test outside the loop over j
.
Use advanced data structures
for(int j=0;j<words[i].length();j++)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
}
takes time proportional to words[i].length() * letters.length
. If you use java.util.HashMap<Character, Integer>
to store a per-character count, you can generate a representation for each word in time proportional to the length of the word, and you can compare the representations of two words in time proportional to the length of each word. In this toy example it doesn't matter, but for real applications the difference between $O(n^2)$ and $O(n)$ can be the difference between a project being feasible and not. The first place to look for optimisations is always the algorithm.
$endgroup$
add a comment |
$begingroup$
Whitespace is very important for readability. For posting to Stack Exchange sites I recommend replacing tabs with spaces, because otherwise the site does that for you and the tabstops might not match. Here, though, the whitespace is so crazy that I think you need to look at configuring your IDE to pretty-print the code. Reformatting so that I can understand the structure:
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
Names
Java convention is that camel-case names which start with a capital letter are types (classes, interfaces, etc), so Search
as the name of a variable is unexpected.
counter
is not entirely uninformative, but a better name would tell me what it counts. Similarly, it would be helpful to distinguish which variables relate to the search query and which to the items searched. The best convention I've seen there is PHP's needle
and haystack
, so I would suggest needleLetters
and haystackWords
.
foreach statement
Instead of for(int i=0;i<words.length;i++) ... words[i]
you can use for (String word : words) ... word
. This removes a variable and simplifies the naming, making it easier to see what the code does.
Decomposing strings
String
has a method toCharArray()
. I think it would make more sense to use that than split("")
.
Don't put something in a loop which can go outside it
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
...
}
}
could be rewritten
if(letters.length==ssplit.length)
{
for(int j=0;j<ssplit.length;j++)
{
...
}
}
Executing the test once is more efficient, and it's also easier to understand because the maintainer doesn't have to reason about loop invariants to work out what might have changed the second time the test is executed.
Since there's nothing after this test in the loop body, an alternative would be
if(letters.length!=ssplit.length)
{
continue;
}
for(int j=0;j<ssplit.length;j++)
{
...
}
Beware hard-coded constants
Why
if (counter == 4)
{
System.out.println(words[i]);
}
? That's a bug. The comparison should be with letters.length
. Also, it would make more sense to move the test outside the loop over j
.
Use advanced data structures
for(int j=0;j<words[i].length();j++)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
}
takes time proportional to words[i].length() * letters.length
. If you use java.util.HashMap<Character, Integer>
to store a per-character count, you can generate a representation for each word in time proportional to the length of the word, and you can compare the representations of two words in time proportional to the length of each word. In this toy example it doesn't matter, but for real applications the difference between $O(n^2)$ and $O(n)$ can be the difference between a project being feasible and not. The first place to look for optimisations is always the algorithm.
$endgroup$
Whitespace is very important for readability. For posting to Stack Exchange sites I recommend replacing tabs with spaces, because otherwise the site does that for you and the tabstops might not match. Here, though, the whitespace is so crazy that I think you need to look at configuring your IDE to pretty-print the code. Reformatting so that I can understand the structure:
public class d3 {
public static void main(String args){
String Search="loop";
String letters = Search.split("") ;
int counter;
String words={"pole","pool","lopo","book","kobo"};
for(int i=0;i<words.length;i++)
{
counter=0;
String ssplit = words[i].split("");
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
if (counter == 4)
{
System.out.println(words[i]);
}
}
}
}
}
}
Names
Java convention is that camel-case names which start with a capital letter are types (classes, interfaces, etc), so Search
as the name of a variable is unexpected.
counter
is not entirely uninformative, but a better name would tell me what it counts. Similarly, it would be helpful to distinguish which variables relate to the search query and which to the items searched. The best convention I've seen there is PHP's needle
and haystack
, so I would suggest needleLetters
and haystackWords
.
foreach statement
Instead of for(int i=0;i<words.length;i++) ... words[i]
you can use for (String word : words) ... word
. This removes a variable and simplifies the naming, making it easier to see what the code does.
Decomposing strings
String
has a method toCharArray()
. I think it would make more sense to use that than split("")
.
Don't put something in a loop which can go outside it
for(int j=0;j<words[i].length();j++)
{
if(letters.length==ssplit.length)
{
...
}
}
could be rewritten
if(letters.length==ssplit.length)
{
for(int j=0;j<ssplit.length;j++)
{
...
}
}
Executing the test once is more efficient, and it's also easier to understand because the maintainer doesn't have to reason about loop invariants to work out what might have changed the second time the test is executed.
Since there's nothing after this test in the loop body, an alternative would be
if(letters.length!=ssplit.length)
{
continue;
}
for(int j=0;j<ssplit.length;j++)
{
...
}
Beware hard-coded constants
Why
if (counter == 4)
{
System.out.println(words[i]);
}
? That's a bug. The comparison should be with letters.length
. Also, it would make more sense to move the test outside the loop over j
.
Use advanced data structures
for(int j=0;j<words[i].length();j++)
{
for(int k=0;k<letters.length;k++)
{
if(letters[j].equals(ssplit[k]))
{
counter++;
ssplit[k]="*";
break;
}
}
}
takes time proportional to words[i].length() * letters.length
. If you use java.util.HashMap<Character, Integer>
to store a per-character count, you can generate a representation for each word in time proportional to the length of the word, and you can compare the representations of two words in time proportional to the length of each word. In this toy example it doesn't matter, but for real applications the difference between $O(n^2)$ and $O(n)$ can be the difference between a project being feasible and not. The first place to look for optimisations is always the algorithm.
answered 4 hours ago
Peter TaylorPeter Taylor
15.9k2759
15.9k2759
add a comment |
add a comment |
$begingroup$
welcome on Codereview.
I am pretty sure that you will find many other ways to do it the comments from @NateGardner is already a good suggestion. But the goal is to review your code so I will just try to suggest some improvements to your code.
First of all I will just reformat the code, create a dedicated class for it and define the input and output.
class WordFinder {
private final String words;
WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
String find(String word) {
// Your code here
}
}
Then you can start to split your nested logic in different methods and use exiting methods to simplify your code (like String#toCharArray()
instead of String#split("")
)
String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( this.matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
As said in the beginning, there is a lot of way to test two words for matching and I am sure that you will find the best one. For this answer, I decided to compare the hash of each array of char
.
Here is my code if you want. But if you can use other structure from the collections or the stream API, this one can be totally different.
public class WordFinder {
private final String words;
public WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
public String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
private boolean matches(char requirement, char candidate) {
return candidate.length==requirement.length &&
hash(candidate)==hash(requirement);
}
private int hash(char array) {
char copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy);
return Arrays.hashCode(copy);
}
}
$endgroup$
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
add a comment |
$begingroup$
welcome on Codereview.
I am pretty sure that you will find many other ways to do it the comments from @NateGardner is already a good suggestion. But the goal is to review your code so I will just try to suggest some improvements to your code.
First of all I will just reformat the code, create a dedicated class for it and define the input and output.
class WordFinder {
private final String words;
WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
String find(String word) {
// Your code here
}
}
Then you can start to split your nested logic in different methods and use exiting methods to simplify your code (like String#toCharArray()
instead of String#split("")
)
String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( this.matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
As said in the beginning, there is a lot of way to test two words for matching and I am sure that you will find the best one. For this answer, I decided to compare the hash of each array of char
.
Here is my code if you want. But if you can use other structure from the collections or the stream API, this one can be totally different.
public class WordFinder {
private final String words;
public WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
public String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
private boolean matches(char requirement, char candidate) {
return candidate.length==requirement.length &&
hash(candidate)==hash(requirement);
}
private int hash(char array) {
char copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy);
return Arrays.hashCode(copy);
}
}
$endgroup$
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
add a comment |
$begingroup$
welcome on Codereview.
I am pretty sure that you will find many other ways to do it the comments from @NateGardner is already a good suggestion. But the goal is to review your code so I will just try to suggest some improvements to your code.
First of all I will just reformat the code, create a dedicated class for it and define the input and output.
class WordFinder {
private final String words;
WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
String find(String word) {
// Your code here
}
}
Then you can start to split your nested logic in different methods and use exiting methods to simplify your code (like String#toCharArray()
instead of String#split("")
)
String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( this.matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
As said in the beginning, there is a lot of way to test two words for matching and I am sure that you will find the best one. For this answer, I decided to compare the hash of each array of char
.
Here is my code if you want. But if you can use other structure from the collections or the stream API, this one can be totally different.
public class WordFinder {
private final String words;
public WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
public String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
private boolean matches(char requirement, char candidate) {
return candidate.length==requirement.length &&
hash(candidate)==hash(requirement);
}
private int hash(char array) {
char copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy);
return Arrays.hashCode(copy);
}
}
$endgroup$
welcome on Codereview.
I am pretty sure that you will find many other ways to do it the comments from @NateGardner is already a good suggestion. But the goal is to review your code so I will just try to suggest some improvements to your code.
First of all I will just reformat the code, create a dedicated class for it and define the input and output.
class WordFinder {
private final String words;
WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
String find(String word) {
// Your code here
}
}
Then you can start to split your nested logic in different methods and use exiting methods to simplify your code (like String#toCharArray()
instead of String#split("")
)
String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( this.matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
As said in the beginning, there is a lot of way to test two words for matching and I am sure that you will find the best one. For this answer, I decided to compare the hash of each array of char
.
Here is my code if you want. But if you can use other structure from the collections or the stream API, this one can be totally different.
public class WordFinder {
private final String words;
public WordFinder(String words) {
this.words = new String[words.length];
System.arraycopy(words, 0, this.words, 0, words.length);
}
public String find(String word) {
String result = new String[this.words.length];
char letters = word.toCharArray();
int counter = 0;
for (String candidate : this.words) {
if ( matches(letters, candidate.toCharArray()) ) {
result[counter++] = candidate;
}
}
return Arrays.copyOf(result, counter);
}
private boolean matches(char requirement, char candidate) {
return candidate.length==requirement.length &&
hash(candidate)==hash(requirement);
}
private int hash(char array) {
char copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy);
return Arrays.hashCode(copy);
}
}
answered 7 hours ago
gervais.bgervais.b
1,083410
1,083410
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
add a comment |
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
$begingroup$
The most significant suggestion of this answer introduces a bug. Comparing hashes is a valid way of showing that two objects are different, but it is not a valid way of showing that they're the same.
$endgroup$
– Peter Taylor
4 hours ago
add a comment |
Aditya is a new contributor. Be nice, and check out our Code of Conduct.
Aditya is a new contributor. Be nice, and check out our Code of Conduct.
Aditya is a new contributor. Be nice, and check out our Code of Conduct.
Aditya is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f211538%2fgiven-a-word-how-do-i-find-other-words-in-an-array-with-same-length-and-same-ch%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
Hi Aditya. Do you have to use arrays for the words and characters or can you use another structure ?
$endgroup$
– gervais.b
15 hours ago
$begingroup$
@gervais.b I'm currently not too familiar with other data structures. But I'm open to suggestions. Is there a better option than using arrays?
$endgroup$
– Aditya
12 hours ago
$begingroup$
@PeterTaylor Thank you for pointing out the bug. I'll try to fix it and update the question as soon as possible.
$endgroup$
– Aditya
12 hours ago
$begingroup$
Just for inspiration, here's something to consider, without going into the depth of a full answer. If I understand correctly, your goal is to return all the words from your dictionary that contain the same length and character set as your input word. One approach might be to take your dictionary and for every word sort the characters in alphabetical order. Then generate a one-to-many map of the sorted versions of the words to all the words they can make up. Then, once you possess such a map, perform the same operation on the input word, and you're returning a simple key/value lookup; O(1).
$endgroup$
– Nate Gardner
9 hours ago
$begingroup$
The advantage to such an approach would be that it can process your dictionary offline, offloading the work of testing for your condition and effectively creating a hash index for your search criteria. While generating such a map might take a while, it would only need to be done when the dictionary is modified, while making your performance of searching for these words extremely good, since you can instantly skip to your answer without ever processing any irrelevant words. This approach would make sense if you have a dictionary that stays the same for many inputs.
$endgroup$
– Nate Gardner
9 hours ago