3
\$\begingroup\$

I applied for Junior Java Developer in some company. Got a task:"Listing words (without duplicates) from text, provide lines where appears, count them." Output should looks like:

Alphacoronavirus - 3 - pozycje -> [1,3,2]

gatunki - 4 - pozycje -> [1,3,2,7]

Koronawirusy - 2 - pozycje -> [3,2]

Wirusów - 1 - pozycje -> [1]

Did not receive any feedback form them for two weeks so i will ask for judgment here. Waiting for roast

Data structure:

import java.util.ArrayList;
import java.util.List;

public class PatternStats implements Comparable<PatternStats>{
    private String word;
    private int amountOfAppearances = 1;
    private List<Integer> linesContains = new ArrayList<>();

    public PatternStats(String word){
        this.word = word;
    }

    public String getWord() {
        return word;
    }

    public int getAmountOfAppearances() {
        return amountOfAppearances;
    }

    public List<Integer> getLinesContains() {
        return linesContains;
    }

    public void increaseAOA(){
        this.amountOfAppearances++;
    }

    public void addLineToList(int lineNO){
        this.linesContains.add(lineNO);
    }

    @Override
    public int compareTo(PatternStats o) {
        int compareInt = this.word.toLowerCase().compareTo(o.word.toLowerCase());
        if(compareInt < 0) return -1;
        if(compareInt > 0) return  1;
        return 0;
    }
}

WordLister

import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WordListingWithMap {

    private Map<String, PatternStats> patternStatsMap = new HashMap<>();

    public List<PatternStats> listWords(String filePath) {
        patternStatsMap.clear();
        String regex = "\\b[^\\d\\P{L}]+\\b";
        try {
            FileInputStream fis = new FileInputStream(filePath);
            Scanner sc = new Scanner(fis);
            scanTextCollectWords(sc, regex);
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<PatternStats> patternStats = new ArrayList<>(patternStatsMap.values());
        Collections.sort(patternStats);
        return patternStats;
    }

    private void scanTextCollectWords(Scanner sc, String regex) {
        int lineCounter = 0;
        while (sc.hasNextLine()){
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(sc.nextLine());
            lineCounter++;
            while (m.find()) {
                if (patternStatsMap.containsKey(m.group(0))) {
                    increaseExist(m.group(0), lineCounter);
                } else {
                    createNewAddToMap(m.group(0), lineCounter);
                }
            }
        }
    }

    private void createNewAddToMap(String word, int line) {
        PatternStats tempPatternStats = new PatternStats(word);
        tempPatternStats.addLineToList(line);
        patternStatsMap.put(word, tempPatternStats);
    }

    private void increaseExist(String word, int line) {
        if (!patternStatsMap.get(word).getLinesContains().contains(line))
            patternStatsMap.get(word).addLineToList(line);

        patternStatsMap.get(word).increaseAOA();
    }
}

and Main

import java.util.List;

public class Main {

    public static void main(String[] args) {
        final String filePatch = "C:\\vaTast\\src\\zadanie.txt";

        WordListingWithMap wlwm = new WordListingWithMap();
        toPrint = wlwm.listWords(filePatch);
        for (PatternStats each : toPrint){
            System.out.println(each.getWord() + " - " +
                    each.getAmountOfAppearances() + " - pozycje - > " +
                    each.getLinesContains());
        }
    }
}

repo: https://github.com/krukarkonrad/vaRepo/

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to Code Review, I have a question : words like Apple and apple are considered equal ? \$\endgroup\$ May 30 '20 at 20:44
  • \$\begingroup\$ I asked company the same(while sending repo), didn't get any answare. Imo it's just to add .toLowerCase() in right place \$\endgroup\$
    – Konrad
    May 31 '20 at 8:06
2
\$\begingroup\$

Your code and output are correct, for me there is a hint in the description of the task :

Listing words (without duplicates) from text, provide lines where appears, count them.

For me the words without duplicates mean that a structure like Set well adapts to the constraint so instead of:

public class PatternStats implements Comparable<PatternStats>{
    private String word;
    private int amountOfAppearances = 1;
    private List<Integer> linesContains = new ArrayList<>();
}

you could define the PatternStats class the following way:

public class PatternStats implements Comparable<PatternStats>{
    private int amountOfAppearances;
    private SortedSet<Integer> linesContains; 
    private String word;

    public PatternStats(String word){
        this.amountOfAppearances = 1;
        this.linesContains = new TreeSet<>();
        this.word = word;
    }

    ...other methods
}

Your comparing method:

@Override
public int compareTo(PatternStats o) {
    int compareInt = this.word.toLowerCase().compareTo(o.word.toLowerCase());
    if(compareInt < 0) return -1;
    if(compareInt > 0) return  1;
    return 0;
}

can be rewritten in this way using compareToIgnoreCase:

@Override
public int compareTo(PatternStats o) {
    return word.compareToIgnoreCase(o.word);
}

You can override the toString method returning the output you expect so your class can be rewritten in this way :

PatternStats.java

public class PatternStats implements Comparable<PatternStats>{
    private int amountOfAppearances;
    private SortedSet<Integer> linesContains; 
    private String word;

    public PatternStats(String word){
        this.amountOfAppearances = 1;
        this.linesContains = new TreeSet<>();
        this.word = word;
    }

    public String getWord() {
        return word;
    }

    public int getAmountOfAppearances() {
        return amountOfAppearances;
    }

    public SortedSet<Integer> getLinesContains() {
        return linesContains;
    }

    public void increaseAOA(){
        ++amountOfAppearances;
    }

    public void addLineToSet(int lineNO){
        this.linesContains.add(lineNO);
    }

    @Override
    public int compareTo(PatternStats o) {
        return word.compareToIgnoreCase(o.word);
    }

    @Override
    public String toString() {
        return String.format("%s - %d - pozycje - > %s", word, amountOfAppearances, linesContains);
    }

}

In your class WordListingWithMap you are reading a file line by line compiling and using the same regex for every line to match words: you can compile the regex one time like below:

public class WordListingWithMap {
    private static final String REGEX = "\\b[^\\d\\P{L}]+\\b";
    private static final Pattern PATTERN = Pattern.compile(REGEX);
    private int lineCounter;
    private Map<String, PatternStats> patternStatsMap;

    public WordListingWithMap() {
        this.patternStatsMap = new HashMap<>();
        this.lineCounter = 1;
    }

    ...other methods
}

Instead of reading a file using a FileInputStream you can use the Files class to make the code shorter like below:

WordListingWithMap.java

public class WordListingWithMap {
    private static final String REGEX = "\\b[^\\d\\P{L}]+\\b";
    private static final Pattern PATTERN = Pattern.compile(REGEX);
    private int lineCounter;
    private Map<String, PatternStats> patternStatsMap;

    public WordListingWithMap() {
        this.patternStatsMap = new HashMap<>();
        this.lineCounter = 1;
    }

    public List<PatternStats> listWords(String filePath) {
        try(Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.forEach(l -> scanTextCollectWords(l, lineCounter++));         
        } catch (IOException e) {
            e.printStackTrace();
        }
        List<PatternStats> patternStats = new ArrayList<>(patternStatsMap.values());
        Collections.sort(patternStats);
        return patternStats;
    }

    private void scanTextCollectWords(String line, int lineCounter) {
        Matcher m = PATTERN.matcher(line);

        while (m.find()) {
            String word = m.group(0);
            if (patternStatsMap.containsKey(word)) {
                increaseExist(word, lineCounter);
            } else {
                createNewAddToMap(word, lineCounter);
            }
        }
    }

    private void createNewAddToMap(String word, int line) {
        PatternStats tempPatternStats = new PatternStats(word);
        tempPatternStats.addLineToSet(line);
        patternStatsMap.put(word, tempPatternStats);
    }

    private void increaseExist(String word, int line) {
        patternStatsMap.get(word).addLineToSet(line);
        patternStatsMap.get(word).increaseAOA();
    }
}

Your Main class can be rewritten in this way:

Main.java

public class Main {

    public static void main(String[] args) {
        final String filePath = "zadanie.txt";

        WordListingWithMap wlwm = new WordListingWithMap();
        wlwm.listWords(filePath).forEach(System.out::println);
    }
}

\$\endgroup\$
2
  • \$\begingroup\$ Holy Moly! Didn't expect that! Thank You! For sure I will learn sth more by this answer! BTW: Overall what do you think about my solution as a Junior Dev assignment? \$\endgroup\$
    – Konrad
    Jun 1 '20 at 9:27
  • 1
    \$\begingroup\$ @Konrad You are welcome. Your code is certainly correct and for me your solution is surely good as a Junior Dev assignment. The only advice I can give you is to check std library if functions you need are already implemented to make the code shorter, for me your solution you would have passed the test without any effort. \$\endgroup\$ Jun 1 '20 at 9:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.