Why is sequential file naming not working? - java

I am trying to solve this question.
Problem Statement
You are developing a File Manager but encountered a problem. You realised that two files cannot have the same names and if a conflict arises, the file which came later has to be appended with a number N such that N is the smallest positive number that is not used with that particular file name. The number is append in the form of file_name(N). Write a code to solve your problem. You will be given an array of strings of file names. You need to assume that if a file name appears earlier in an array, it was created first.
NOTE: file_name and file_name(2) are two different file names i.e if a file name already has a number appended to it, its a different file name.
Input
The first line contains N, the number of strings.
The next line contains N space-separated strings (file names).
Output
Print the names of files, after making the necessary changes separated by space.
Constraints
1 ≤ N ≤ 50
1 ≤ file_name.length ≤ 25
filename has no white space characters
Sample Input
7
file sample sample file file file(1) file(1)
Sample Output
file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)
Below is my code. When I tested it with my own file names, it renames well but when I submit it, the tests fail. I would like to know what's wrong with my code and why its not working.
import java.util.Scanner;
public class Dcoder {
public static void main (String[] args) {
Scanner scanner = new Scanner (System.in);
// Read number of file names and create
// an array to hold them
String[] fileNames = new String[scanner.nextInt ()];
// Fill the array with the supplied names
// from System.in
for (int i = 0; i < fileNames.length; i++)
fileNames [i] = scanner.next ();
// Modify the file names
for (String fileName : fileNames) {
int count = 0;
for (int i = 0; i < fileNames.length; i++)
if (fileName.equals (fileNames [i])) {
fileNames [i] = fileNames [i] + (count == 0 ? "" : "(" + count + ")");
count++;
}
}
// Print out the modified list of file names
for (String fileName : fileNames)
System.out.print (" " + fileName);
}
}

If all tests fail, then it is likely because your output has a space before the first name.
The output should be the file name, space-separated, not space-prefixed.
If you try input "file file(1) file file", your code outputs
file file(1) file(1)(1) file(2)
but correct output is
file file(1) file(2) file(3)
For better performance, you should use a Set.
static void printUnique(String... fileNames) {
Set<String> used = new HashSet<>();
for (int i = 0; i < fileNames.length; i++) {
String newName = fileNames[i];
for (int j = 1; ! used.add(newName); j++)
newName = fileNames[i] + "(" + j + ")";
if (i != 0)
System.out.print(" ");
System.out.print(newName);
}
System.out.println();
}
Test
printUnique("file", "sample", "sample", "file", "file", "file(1)", "file(1)");
printUnique("file", "file(1)", "file", "file");
Output
file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)
file file(1) file(2) file(3)

Your solution is a procedural approach to the Problem.
Procedural approaches are not bad on their own.
But Java is an Object Oriented programming language and if you want to become a good Java programmer you should start looking for more OO-like solutions.
But OOP doesn't mean to "split up" code into random classes.
The ultimate goal of OOP is to reduce code duplication, improve readability and support reuse as well as extending the code.
Doing OOP means that you follow certain principles which are (among others):
information hiding / encapsulation
single responsibility
separation of concerns
KISS (Keep it simple (and) stupid.)
DRY (Don't repeat yourself.)
"Tell! Don't ask."
Law of demeter ("Don't talk to strangers!")
So what could a more OO-like approach look like?
The underlaying question of that problem is: "How often does a specific file name appear in the input?" We want to find an association between Strings (file Names) and integer values (number of occurrence). This could be represented as a Map<String,Integer>. The whole logic is as simple as looking in the output if the current fileName already exists there and if so add the counter suffix. This means we need another Collection to hold the output.
My Solution would look like this:
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class FileNameCounter {
public List<String> renameDoubledFiles(List<String> input) {
Map<String, Integer> occurrencesOfNames = new HashMap<>();
LinkedList<String> output = new LinkedList<>();
for (String fileName : input) {
if (output.contains(fileName)) {
Integer counter = updateCountFor(fileName, occurrencesOfNames);
String suffixedName = appendCounterSuffix(fileName, counter);
output.add(suffixedName);
} else {
output.add(fileName);
}
}
return output;
}
private Integer updateCountFor(String fileName, Map<String, Integer> occurrencesOfNames) {
Integer counter = occurrencesOfNames.getOrDefault(fileName, Integer.valueOf(0));
occurrencesOfNames.put(fileName, ++counter);
return counter;
}
private String appendCounterSuffix(String fileName, Integer counter) {
return String.format("%s(%d)", fileName, counter);
}
}
and here is the JUnit test to prove that it works:
import static org.junit.jupiter.api.Assertions.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
class FileNameCounterTest {
#Test
void test() {
List<String> input = Arrays.asList("file sample sample file file file(1) file(1)".split(" "));
List<String> renamedDoubledFiles = new FileNameCounter().renameDoubledFiles(input);
String output = renamedDoubledFiles.stream().collect(Collectors.joining(" "));
assertEquals("file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)", output);
}
}

Related

Is there a Java function that can read a dictionary file and output the definition when asked for a word in standard input? [duplicate]

This question already has answers here:
Array Required, but java.lang.String found
(2 answers)
Closed 11 months ago.
I have a file definitions.dict which contains words and their respective definitions. A snippet of the file looks like this:
dictionary ? a book or electronic resource that gives a list of the words of a language in alphabetical order and explains what they mean
word ? a single unit of language that means something and can be spoken or written
computer ? an electronic machine that can store, organise and find information, do processes with numbers and other data, and control other machines
I'm trying to write Java code, that takes the word as standard input and outputs the definition of said word. The code I've written so far fails to even compile, giving the error:
Dictionary.java:25: error: array required, but String found
if(searchword.equals(line[i][0])){
^
Dictionary.java:26: error: array required, but String found
System.out.println(line[i][1]);
^
Here is the code I have so far:
import java.util.*;
import java.io.*;
public class Dictionary {
public static void main(String[] args) throws FileNotFoundException {
String searchword = "";
String[] line = {};
int i;
Scanner scanword = new Scanner(System.in);
if(scanword.hasNextLine()){
searchword = scanword.nextLine();
}
try{
Scanner scan = new Scanner(new File("sample.dict"));
while (scan.hasNextLine()){
line = Arrays.copyOf(line, line.length + 1);
line[line.length-1] = scan.nextLine();
}
for(i = 0; i < line.length; i++) {
line[i].split("\\ ? ");
if(searchword.equals(line[i][0])){
System.out.println(line[i][1]);
}
}
}
catch (FileNotFoundException ex) {
;
}
}
}
I will admit that this is part of an assignment which I've been struggling with for a while and I am asking here as a last resort.
(Note that I am only allowed to work with arrays and no other data structure.)
Slighlty different approach but what I did was actually create a dictionary object with two parameters:
public String term;
public String definition;
Then had a method to load dictionary objects into a Dictionary[] array from my sample.dict.
So then all I had to do in my main method was something like:
Dictionary[] definitions = loadDefinitions(f);
while (scan.hasNext()){
String userInput = scan.next();
for (int i = 0; i<definitions.length-1;i++){
if(userInput.contentEquals(definitions[i].term)){
System.out.println(definitions[i].definition);
Hope that logic kinda makes sense. Good luck on the task! (Have a look at the athletes tutorial example :) )

Item Counter program that will display the number of names that are stored on a file

Can someone help me with this java program that I've been puzzled on for a while. I'll post the question alone with the code but its a Files in java that I've recently started and I'm having trouble adding a loop counter variable to hold and display the number of names stored in the file.
For better understanding here the question I'm working on:
Assume that a file containing a series of names (as strings) is named names.dat and exists on the computers disk. Design a program that displays the number of names that are stored in the file. (Hint: Open the file and read every string stored in it. Each time you read a string, increment a counter variable. When you've read all the strings from the file, the counter variable will contain the number of names stored in the file.)
I don't know how much trouble it will be to aid assist being that this question is file related in java.
Here is my java code so far for better understanding:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Item_Counter {
public static void main(String[] args) throws FileNotFoundException {
int numLines = 0;
int sum = 0;
File namesFile = new File("C:\\Users\\Tyrese\\JAVA 2\\Chapter 10\\names.dat");
Scanner bot = new Scanner(namesFile);
System.out.println(bot.nextLine());
while (bot.hasNext()) {
numLines = numLines + 1;
numLines = bot.nextInt();
}
System.out.println("The file has" + numLines);
}
}
Feel free to replace my file path and name that is a simple notepad document containing a few names, with your own if necessary.
You have some errors in your code, the way Scanner works for file reading is simple, you open the file the way you did like this : Scanner bot = new Scanner(namesFile); but in order to go to the next line you need to do bot.nextLine() so if you do it before you are in the while or do it twice it will go on 2 lines, so you just need to do like this :
public static void main(String[] args) throws FileNotFoundException {
int numLines = 0; // initialise variable
File namesFile = new File("C:\\Users\\Tyrese\\JAVA 2\\Chapter 10\\names.dat"); // fetch the file
Scanner bot = new Scanner(namesFile); // open the file
while (bot.hasNextLine()) { // while the file has a next line -> go on
numLines++; // add +1 to the variable numLines
numLines = bot.nextLine(); // go to the next line (if it has one)
}
System.out.println("The file has" + numLines); // print the result
}
You can ask me if you have any further questions
This is the problematic part of your code:
System.out.println(bot.nextLine());
while (bot.hasNext()) {
numLines = numLines + 1;
numLines = bot.nextInt();
}
Your println types a line being read and therefore that line will be ignored later. You need hasNextLine in the while loop and nextLine instead of nextInt.
Fix:
while (bot.hasNextLine()) {
numLines = numLines + 1;
bot.nextLine();
}
You can compute the sum of integers inside a file similarly. However, the actual solution depends on the structure of the file. If the file contains the integers as lines, without white characters beside the newline, such as
1
5
4
7
2
7
then the solution is:
int sum = 0;
while (bot.hasNextLine()) {
sum += 1;
bot.nextLine();
}
however, if the file is a list of numbers, separated by space, such as
3 7 8 2 8 3 6 9
then you read the content of the file via
String content = bot.nextLine();
String[] splited = str.split("\\s+");
int sum = 0;
for (int index = 0; index < splited.length; index++) {
sum += Integer.parseInt(splited[index])
}

Print Total Number of Different Words (case sensitive) from a file

**Edit after reviewing Tormod's answer and implementing his advice.
As the title states I'm attempting to print the total number of different words after receiving a file name from command line input. I receive the following message after attempting to compile the program:
Note: Project.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Here is my code. Any help is greatly appreciated:
import java.lang.*;
import java.util.*;
import java.io.*;
public class Project {
public static void main(String[] args) throws IOException {
File file = new File(args[0]);
Scanner s = new Scanner(file);
HashSet lib = new HashSet<>();
try (Scanner sc = new Scanner(new FileInputStream(file))) {
int count = 0;
while(sc.hasNext()) {
sc.next();
count++;
}
System.out.println("The total number of word in the file is: " + count);
}
while (s.hasNext()) {
String data = s.nextLine();
String[] pieces = data.split("\\s+");
for (int count = 0; count < pieces.length; count++)
{
if(!lib.contains(pieces[count])) {
lib.add(pieces[count]);
}
}
}
System.out.print(lib.size());
}
}
I would implement it using a HashSet Add all the words, and read out the size. If you want to make it case insensitive just manipulate all the words to uppercase or something like that. this uses some memory but...
one problem you got with the algorithm is that you do only have one "words". it only holds the words at the same line. so you only count same words at the same line.
HashSet stores strings by their hash value, and thus stores one word only one time.
construction: HashSet lib = new HashSet<>();
inside the loop: if(!lib.contains(word)){lib.add(word);}
check the word count: lib.size()
for(String s : words) {
if(s.equals(word))
count++;
}
You are comparing the words to an empty String, since it's a word it's always gonna be false.
Like Tormod said, the best would be to store the words in a HashSet, as it won't keep duplicates. Then just read out its size.

search sub words in word from array of words?

I have been working on an assignment in that I have to read words from a file and find the longest word and check how many sub words contains in that longest word?
this should work for all the words in the file.
I tried using java the code I wrote works for the small amount of data in file but my task is to process huge amount of data.
Example:
File words: "call","me","later","hey","how","callmelater","now","iam","busy","noway","nowiambusy"
o/p:
callmelater : subwords->call,me,later
In this I'm reading file words storing in linked list and then finding the longest word & removing it from the list then checking how many sub-words extracted word contains.
Main Class Assignment:
import java.util.Scanner;
public class Assignment {
public static void main (String[] args){
long start = System.currentTimeMillis();;
Assignment a = new Assignment();
a.throwInstructions();
Scanner userInput = new Scanner(System.in);
String filename = userInput.nextLine();
// String filename = "ab.txt";
// String filename = "abc.txt";
Logic testRun = new Logic(filename);
// //testRun.result();
long end = System.currentTimeMillis();;
System.out.println("Time taken:"+(end - start) + " ms");
}
public void throwInstructions(){
System.out.println("Keep input file in same directory, where the code is");
System.out.println("Please specify the fie name : ");
}
Subclass Logic for processing:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Logic {
private String filename;
private File file;
private List<String> words = new LinkedList<String>();
private Map<String, String> matchedWords = new HashMap();
#Override
public String toString() {
return "Logic [words=" + words + "]";
}
// constructor
public Logic(String filename) {
this.filename = filename;
file = new File(this.filename);
fetchFile();
run();
result();
}
// find the such words and store in map
public void run() {
while (!words.isEmpty()) {
String LongestWord = extractLongestWord(words);
findMatch(LongestWord);
}
}
// find longest word
private String extractLongestWord(List<String> words) {
String longWord;
longWord = words.get(0);
int maxLength = words.get(0).length();
for (int i = 0; i < words.size(); i++) {
if (maxLength < words.get(i).length()) {
maxLength = words.get(i).length();
longWord = words.get(i);
}
}
words.remove(words.indexOf(longWord));
return longWord;
}
// find the match for word in array of sub words
private void findMatch(String LongestWord) {
boolean chunkFound = false;
int chunkCount = 0;
StringBuilder subWords = new StringBuilder();
for (int i = 0; i < words.size(); i++) {
if (LongestWord.indexOf(words.get(i)) != -1) {
subWords.append(words.get(i) + ",");
chunkFound = true;
chunkCount++;
}
}
if (chunkFound) {
matchedWords.put(LongestWord,
"\t" + (subWords.substring(0, subWords.length() - 1))
+ "\t:Subword Count:" + chunkCount);
}
}
// fetch data from file and store in list
public void fetchFile() {
String word;
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
while ((word = br.readLine()) != null) {
words.add(word);
}
fr.close();
br.close();
} catch (FileNotFoundException e) {
// e.printStackTrace();
System.out
.println("ERROR: File -> "
+ file.toString()
+ " not Exists,Please check filename or location and try again.");
} catch (IOException e) {
// e.printStackTrace();
System.out.println("ERROR: Problem reading -> " + file.toString()
+ " File, Some problem with file format.");
}
}
// display result
public void result() {
Set set = matchedWords.entrySet();
Iterator i = set.iterator();
System.out.println("WORD:\tWORD-LENGTH:\tSUBWORDS:\tSUBWORDS-COUNT");
while (i.hasNext()) {
Map.Entry me = (Map.Entry) i.next();
System.out.print(me.getKey() + ": ");
System.out.print("\t" + ((String) me.getKey()).length() + ": ");
System.out.println(me.getValue());
}
}
}
This is where my programs lacks and goes into some never ending loop.
Complexity of my program is high.
To reduce the processing time I need an efficient approach like Binary/merge sort approach which will take least time like O(log n) or O(nlog n).
If someone can help me with this or at least suggestion in which direction I should proceed. Also please suggest me which programming language would be good to implement such text processing tasks in fast way ?
Thanks in advance
This problem requires a Trie. But you have to augment your trie: a generic one will not do. Geek Viewpoint has a good Trie written in Java. Where your particular work will happen is in the method getWordList. Your getWordList will take as input the longest word (i.e. longestWord) and then try to see if each substring comprises words that exist in the dictionary. I think I have given you enough -- I can't do your work for you. But if you have further question, don't hesitate to ask.
Other than in getWordList, you might be able to pretty much keep the trie from Geek Viewpoint the way it is.
You are also in luck because Geek Viewpoint demonstrates the trie using a Boggle example and your problem is a very very trivial version of Boggle.
Not sure I understand your context, but from reading the problem description it sounds to me like a Linked List is an inappropriate data structure. You don't need to check every single word to the longest word.
A "trie" is probably a perfect data structure for this application.
But if you haven't learned about that in your class, then perhaps you can at least cut down your search space with hashtables. While you are doing the initial list processing calculating the longest word, you can simultaneously process each word into a hash table based on first letter. That way, when you are ready to check your longest word for subwords, you can check only those words with first letters in the longest word. (I'm assuming there could be overlapping words, unlike your example.)
Do you know anything about the input you will be receiving? If you have more details about the input word distribution, then you can customize your solution to the data you expect.
If you can choose your language, and time efficiency is important, you might want to switch to C++, as for many applications it's several times faster than Java.

How does the getAllSynonyms method workd in the rita word net package?

Can anyone explain to me how the 'getAllSynonyms' method i have used in the code below works? Every time I run it I get different results. Sometimes the words aren't synonyms at all! What is the significance of the middle argument in the call to the method? Links to any manuals that explain the methods of word net? Apologies if I have violated posting etiquette :).
import rita.wordnet.*;
import java.lang.reflect.Array;
import java.util.*;
public class Blah
{
RiWordnet wordnet;
String word;
void setup()
{
wordnet = new RiWordnet();
word = "car";
String[] poss = wordnet.getPos(word);
//System.out.println(poss)
for (int j = 0; j < poss.length; j++) {
System.out.println("\n\nSynonyms for " + word + " (pos: " + poss[j] + ")");
String[] synonyms = wordnet.getAllSynonyms(word,poss[0],10);
Arrays.sort(synonyms);
for (int i = 0; i < 5; i++) {
System.out.println(synonyms[i]);
}
}
}
public static void main(String args[])
{
Blah b=new Blah();
b.setup();
}
}
Documentation is here (just click the method names in the right column):
http://www.rednoise.org/rita/wordnet/documentation/
But I have to admit it is not very detailed.
When I run this, I repeatedly get
poss = [n]
synonyms = [chip, diode, microchip, thermistor]
If you don't, you may want to check if you have multiple versions of WordNet JARs in your classpath (the word lists are inside the Jar in a folder called rita/wordnet/wdict.dat)
You can use Arrays.toString() to easily print the contents of an array for debugging, without having to use a for loop every time.
The middle argument ('n') in this case is the word class ("a" = adjective, "n" = noun, "r" = adverb, "v" = verb) since some words (like "good") may exist in multiple classes and each of them has individual synonyms.
In the current version of RiTa, you can call randomizeResults(false); to disable this behavior (though you will now need to download WordNet itself separately):
import rita.*;
import java.util.*;
public static void main(String[] args)
{
RiWordNet rw = new RiWordNet("/WordNet-3.1"); // point to local installation
rw.randomizeResults(false); // don't randomize results
String[] s = rw.getAllSynonyms("car", "n");
System.out.println(Arrays.asList(s));
}

Categories

Resources