Comparting two ArrayList<String> lists in Java - java

Okay... So what I've been trying to do is compare two lists: words and d. The words they have in common need to be added to a third list: realWords.
Dictionary is just a list in a different class that has a bunch of words in it.
List<String> realWords = new ArrayList<String>();
Dictionary d = new Dictionary();
These are the things I've tried and haven't worked (and by "worked" I mean the output is nothing, no errors):
Attempt 1
List<String> realWords = new ArrayList<String>(words);
realWords.retainAll(d);
Attempt 2
for(int i = 0; i < words.size(); i++) {
if (d.contains(words.get(i))){
realWords.add(words.get(i));
}
}
Attempt 3
for(String word : words) {
if (d.contains(word)) {
realWords.add(word);
}
}
Attempt 4
for (int i = 0; i < words.size(); i++) {
for (int j = 0; i < d.size(); i++) {
if(words.get(i) == d.get(j)) {
realWords.add(words.get(i));
}
}
}
And then after that portion of code I'm missing:
return realWords;
Thanks in advance!
Edit1: The code for Dictionary.java is:
package a1;
import java.util.*;
public class Dictionary extends ArrayList<String> {
public Dictionary() {
this.add("abalone");
this.add("abandon");
this.add("abashed");
this.add("abashes");
this.add("abasing");
this.add("abating");
this.add("abdomen");
this.add("abducts");
this.add("abetted");
this.add("abetter");
this.add("abettor");
this.add("abiding");
this.add("ability");
this.add("abjured");
this.add("abjures");
this.add("abolish");
this.add("aborted");
this.add("abounds");
this.add("abraded");
// and then more words
}
}
NOTE: This code was provided to us and cannot be changed.

The following code has the following output: [abalone, abolish]
The problem must be somewhere else. Are you sure that "words" contains valid words? Try outputting it and checking manually.
public class Example {
public static class Dictionary extends ArrayList<String> {
public Dictionary() {
this.add("abalone");
this.add("abandon");
this.add("abashed");
this.add("abashes");
this.add("abasing");
this.add("abating");
this.add("abdomen");
this.add("abducts");
this.add("abetted");
this.add("abetter");
this.add("abettor");
this.add("abiding");
this.add("ability");
this.add("abjured");
this.add("abjures");
this.add("abolish");
this.add("aborted");
this.add("abounds");
this.add("abraded");
// and then more words
}
}
public static void main(String[] args) {
List<String> realWords = new ArrayList<String>(
Arrays.asList("abalone", "foobar", "abolish"));
Dictionary d = new Dictionary();
realWords.retainAll(d);
System.out.println(realWords);
}
}
EDIT: Your other attempts are functionally identical, they have the same complexity (O(words.size() * d.size()) but are longer and less obvious/clear.

The code works fine, please debug your code. See the output for reference.
public static void main(String[] args) {
List<String> words = new ArrayList<String>();
words.add("abashes");
words.add("sdqad");
words.add("abducts");
words.add("sadadads");
List<String> realWords = new ArrayList<String>();
Dictionary d = new Dictionary();
for (int i = 0 ; i < words.size() ; i++) {
if (d.contains(words.get(i))) {
realWords.add(words.get(i));
}
}
System.out.println(realWords);
}
output
[abashes, abducts]

Using Java 8 streams I would suggest:
List<Strings> realWords = words.stream()
.filter(d::contains).collect(Collectors.toList());

You can use an enhance for loop
List<String> realWords = new ArrayList<>();
Dictionary d = new Dictionary();
List<String> words = new ArrayList<String>();
words.add("abetted");
words.add("ability");
for (String word : words) {
if (d.contains(word)) {
realWords.add(word);
}
}
System.out.println(realWords);
}
}

Related

Is there any chance to get rid of that error?(Memory Limit Exceeded)

Here is a problem:
Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK.
Note:
If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string. For example, the itinerary ["JFK", "LGA"] has a smaller lexical order than ["JFK", "LGB"].
All airports are represented by three capital letters (IATA code).
You may assume all tickets form at least one valid itinerary.
Unfortunately i get all the time these errors
Line 63: error: cannot find symbol [in MainClass.java]
list.add(stringToStringList(cols.toString()));
^ symbol: method stringToStringList(String) location: class MainClass Line 83: error: cannot find symbol [in
MainClass.java]
List> tickets = stringToString2dList(line);
^ symbol: method stringToString2dList(String) location: class MainClass 2 errors
Here is my code:
class Solution {
class Checker implements Comparator<String>{
#Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
}
public List<String> findItinerary(List<List<String>> tickets){
String begin="JFK";
final String example=begin;
List<String> solution = new ArrayList<>();
long counter=tickets.stream().filter(lister->lister.get(0).equals(example)).count();
List<String> lexic=tickets.stream().filter(lister->lister.get(0).equals("JFK")).map(p->p.get(1)).distinct().collect(Collectors.toList());
Comparator<String> comparator =new Checker();
lexic.sort(comparator);
solution.add(begin);
begin=lexic.get(0);
System.out.println(counter);
for(int i=0;i<tickets.size();i++) {
if(tickets.get(i).get(0).equals(begin)) {
if(!solution.contains(begin)) {
solution.add(begin);
}
begin=tickets.get(i).get(1);
solution.add(begin);
i=-1;
}
}
return solution;
}
}
public class MainClass {
public static String[] stringToStringArray(String line) {
JsonArray jsonArray = JsonArray.readFrom(line);
String[] arr = new String[jsonArray.size()];
for (int i = 0; i < arr.length; i++) {
arr[i] = jsonArray.get(i).asString();
}
return arr;
}
public static List<List<String>> stringToString2dArray(String input) {
JsonArray jsonArray = JsonArray.readFrom(input);
if (jsonArray.size() == 0) {
return new ArrayList<List<String>>();
}
List<List<String>> list = new ArrayList<>(jsonArray.size());
for (int i = 0; i < jsonArray.size(); i++) {
JsonArray cols = jsonArray.get(i).asArray();
list.add(stringToStringList(cols.toString()));
}
return list;
}
public static String stringListToString(List<String> stringList) {
StringBuilder sb = new StringBuilder("[");
for (String item : stringList) {
sb.append(item);
sb.append(",");
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
List<List<String>> tickets = stringToString2dList(line);
List<String> ret = new Solution().findItinerary(tickets);
String out = stringListToString(ret);
System.out.print(out);
}
}
}
You really don't seem to have a stringToStringList method. You'll have to add one, but luckily, it should be quite easy to reuse the stringToStringArray method you already have:
public static String[] stringToStringList(String line) {
return Arrays.asList(stringToStringArray(line));
}

[Hackerrank][Performance Improvement] Similar Destinations

I am currently solving a challenge that I found on Hackerrank and am in need of some assistance in the code optimization/performance department. I've managed to get my code working and returning the right results but it is failing at the final test case with a timeout error. The input is quite large so, that explains why the code is taking longer that expected.
Problem statement: Similar Destinations
I've attempted to think of different ways of pruning my (intermediate) result set but could not come up with something that I did not already have. I believe that the find function could use a bit more tweaking. I've tried my best to reduce the number of paths that the recursive function has to take but ultimately, it has to look at every destination in order to come up with the right results. However, I did terminate a recursive path if the number of tags in common between destinations were below the min limit. Is there anything else that I could do here?
My code is as follows:-
static class Destination {
String dest;
List<String> tags;
public Destination(String dest, List<String> tags) {
this.dest = dest;
this.tags = tags;
}
#Override
public String toString() {
return dest;
}
}
static List<Destination> allDest = new ArrayList<Destination>();
static int min;
static Set<String> keysTracker = new HashSet<String>();
static Set<String> tagsTracker = new HashSet<String>();
static Map<String, List<String>> keysAndTags = new HashMap<String, List<String>>();
static void find(List<String> commonKey, List<String> commonTags, int index) {
if (index >= allDest.size())
return;
if (commonTags.size() < min)
return;
if (tagsTracker.contains(commonTags.toString()) || keysTracker.contains(commonKey.toString())) {
return;
}
String dest = allDest.get(index).dest;
commonKey.add(dest);
for (int i = index + 1; i < allDest.size(); ++i) {
List<String> tempKeys = new ArrayList<String>(commonKey);
List<String> tags = allDest.get(i).tags;
List<String> tempTags = new ArrayList<String>(commonTags);
tempTags.retainAll(tags);
find(tempKeys, tempTags, i);
if (tempTags.size() >= min) {
if (!tagsTracker.contains(tempTags.toString())
&& !keysTracker.contains(tempKeys.toString())) {
tagsTracker.add(tempTags.toString());
keysTracker.add(tempKeys.toString());
StringBuilder sb = new StringBuilder();
for (int j = 0; j < tempKeys.size(); ++j) {
sb.append(tempKeys.get(j));
if (j + 1 < tempKeys.size())
sb.append(",");
}
keysAndTags.put(sb.toString(), tempTags);
}
}
}
}
public static void main(String[] args) {
init();
sort();
calculate();
answer();
}
static void init() {
Scanner s = new Scanner(System.in);
min = s.nextInt();
s.nextLine();
String line;
while (s.hasNextLine()) {
line = s.nextLine();
if (line.isEmpty())
break;
String[] tokens = line.split(":");
String dest = tokens[0];
tokens = tokens[1].split(",");
List<String> tags = new ArrayList<String>();
for (int j = 0; j < tokens.length; ++j)
tags.add(tokens[j]);
Collections.sort(tags);
Destination d = new Destination(dest, tags);
allDest.add(d);
}
s.close();
}
static void sort() {
Collections.sort(allDest, new Comparator<Destination>() {
#Override
public int compare(Destination d1, Destination d2) {
return d1.dest.compareTo(d2.dest);
}
});
}
static void calculate() {
for (int i = 0; i < allDest.size() - 1; ++i) {
find(new ArrayList<String>(), new ArrayList<String>(allDest.get(i).tags), i);
}
}
static void answer() {
List<Map.Entry<String, List<String>>> mapInListForm = sortAnswer();
for (Map.Entry<String, List<String>> entry : mapInListForm) {
System.out.print(entry.getKey() + ":");
for (int i = 0; i < entry.getValue().size(); ++i) {
System.out.print(entry.getValue().get(i));
if (i + 1 < entry.getValue().size())
System.out.print(",");
}
System.out.println();
}
}
static List<Map.Entry<String, List<String>>> sortAnswer() {
List<Map.Entry<String, List<String>>> mapInListForm =
new LinkedList<Map.Entry<String, List<String>>>(keysAndTags.entrySet());
Collections.sort(mapInListForm, new Comparator<Map.Entry<String, List<String>>>() {
public int compare(Map.Entry<String, List<String>> e1, Map.Entry<String, List<String>> e2) {
if (e1.getValue().size() > e2.getValue().size()) {
return -1;
} else if (e1.getValue().size() < e2.getValue().size()) {
return 1;
}
return e1.getKey().compareTo(e2.getKey());
}
});
return mapInListForm;
}
Any help is greatly appreciated. Thanks!
I've managed to solve the problem after a bit of selective profiling. It would seem that my initial hunch was right. The problem had less to do with the algorithm and more towards the data structures that I was using! The culprit was in the find method. Specifically, when calling the retainAll method on two lists. I had forgotten the that it would take O(n^2) time to iterate through two lists. That was why it was slow. I then changed list into a HashSet instead. As most of us know, a HashSet has an O(1) time complexity when it comes to accessing its values. The retainAll method stayed but instead of finding the intersection between two lists, we now find the intersection between two sets instead! That managed to shave off a couple of seconds off of the total elapsed runtime and all the tests passed. :)
The find method now looks like this:-
static void find(List<String> commonKey, List<String> commonTags, int index) {
if (index >= allDest.size())
return;
if (commonTags.size() < min)
return;
if (tagsTracker.contains(commonTags.toString()) || keysTracker.contains(commonKey.toString())) {
return;
}
String dest = allDest.get(index).dest;
commonKey.add(dest);
for (int i = index + 1; i < allDest.size(); ++i) {
List<String> tempKeys = new ArrayList<String>(commonKey);
List<String> tags = allDest.get(i).tags;
Set<String> tempTagsSet1 = new HashSet<String>(commonTags);
Set<String> tempTagsSet2 = new HashSet<String>(tags);
tempTagsSet1.retainAll(tempTagsSet2);
List<String> tempTags = new ArrayList<String>(tempTagsSet1);
if (tempTags.size() >= min)
Collections.sort(tempTags);
find(tempKeys, tempTags, i);
if (tempTags.size() >= min) {
if (!tagsTracker.contains(tempTags.toString())
&& !keysTracker.contains(tempKeys.toString())) {
tagsTracker.add(tempTags.toString());
keysTracker.add(tempKeys.toString());
StringBuilder sb = new StringBuilder();
for (int j = 0; j < tempKeys.size(); ++j) {
sb.append(tempKeys.get(j));
if (j + 1 < tempKeys.size())
sb.append(",");
}
keysAndTags.put(sb.toString(), tempTags);
}
}
}
}

Compare all values of arraylist to a string

I have an array list abc which has certain values -
ArrayList< String > abc = new ArrayList<>();
abc.add("hi");
abc.add("hello Yash");
abc.add("i am Yash");
String x = "Yash";
Now, I want to know if x is contained in any of the elements of abc.
If it is, then get the index of the elements which contain x.
Here is a simple solution:
public class FindText
{
public static void main(String[] args)
{
ArrayList< String > abc = new ArrayList<>();
abc.add("hi");
abc.add("hello Yash");
abc.add("i am Yash");
String x = "Yash";
for(int i=0; i<abc.size(); i++)
{
if(abc.get(i).contains(x))
{
int index = i;
System.out.println(index);
}
}
}
}
It gives you 1 and 2 as indexes which includes the text "Yash"
You can achieve this in 2 different ways...
The old school
and the lambdas way
Old school Example:
public static void main(String[] args) {
List<String> abc = new ArrayList<>();
abc.add("hi");
abc.add("hello Yash");
abc.add("i am Yash");
String x = "Yash";
List<String> resultOldSchool = new ArrayList<>();
for (String sentence : abc) {
if (sentence.contains(x)) {
resultOldSchool.add(sentence);
}
}
System.out.println(resultOldSchool);
}
Lambdas way Example:
public static void main(String[] args) {
List<String> abc = new ArrayList<>();
abc.add("hi");
abc.add("hello Yash");
abc.add("i am Yash");
String x = "Yash";
List<String> resultJava8 = findStringInList(abc, x);
if (!resultJava8.isEmpty()) {
System.out.println(resultJava8);
}
}
public static List<String> findStringInList(final List<String> list, final String strng) {
return list.stream().filter(s -> s.contains(strng)).collect(Collectors.toList());
}
feel free to decide....
Assuming that abc is a List<String> and x is a String then this should do the trick.
List<Integer> indexes = new LinkedList<Integer>();
for(int i = 0; i < abc.size(); i++)
{
if(abc.get(i).contains(x))
indexes.add(i);
}
After the loop finishes all the indexes of the elements that contain x will be in the indexes list.

java.lang.NullPointerException on filenames

I've tried debugging my program and have found the value of ArrayList<String> fileNames in my private void printFilesIn(String word) to be null. I've read What is a NullPointerException and how do I fix it? and it has been very informative, but I don't understand what I can do to fix the code. It's probably a simple fix in the right place, but I would like to have some help on this.
import edu.duke.*;
import java.util.*;
import java.io.*;
public class WordsInFiles {
private HashMap<String,ArrayList<String>> wordInFilesMap;
public WordsInFiles() {
wordInFilesMap = new HashMap<String,ArrayList<String>>();
}
private void addWordsFromFile(File file) {
FileResource fileResource = new FileResource(file);
String fileName = file.getName();
for (String word : fileResource.words()) {
if (!wordInFilesMap.containsKey(word)) {
ArrayList<String> newList = new ArrayList<String>();
newList.add(fileName);
wordInFilesMap.put(word, newList);
}
else if (wordInFilesMap.containsKey(word)
&& !wordInFilesMap.get(word).contains(fileName)) {
ArrayList<String> currentList = wordInFilesMap.get(word);
currentList.add(fileName);
wordInFilesMap.put(word,currentList);
}
}
}
private void buildWordFileMap() {
wordInFilesMap.clear();
DirectoryResource dirResource = new DirectoryResource();
for (File file : dirResource.selectedFiles()) {
addWordsFromFile(file);
}
}
private int maxNumber() {
//returns the maximum number of files any word appears in, considering
// all words from a group of files.
int highest = 0;
for (String word : wordInFilesMap.keySet()) {
ArrayList<String> currentFileList = wordInFilesMap.get(word);
int currentNum = currentFileList.size();
if (currentNum > highest) {
highest = currentNum;
}
}
return highest;
}
private ArrayList<String> wordsInNumFiles(int number) {
//returns an ArrayList of words that appear in exactly number files
ArrayList<String> wordList = new ArrayList<String>();
for (String word : wordInFilesMap.keySet()) {
ArrayList<String> currentList = wordInFilesMap.get(word);
int currentFileCount = currentList.size();
if (currentFileCount == number) {
wordList.add(word);
}
}
return wordList;
}
private void printFilesIn(String word) {
//prints the names of the files this word appears in, one filename per line
ArrayList<String> fileNames = wordInFilesMap.get(word);
for (int index=0; index < fileNames.size(); index++) { //HERE!!
System.out.println(fileNames.get(index));
}
}
public void tester() {
//call buildWordFileMap to select files and build HashMap of words
buildWordFileMap();
//determine maximum number of files any word is in, considering all words
int fileNum = maxNumber();
System.out.println("Max number files any word is in: "+fileNum);
ArrayList<String> wordsInFiles = wordsInNumFiles(fileNum);
System.out.println("Total words in all files: "+wordsInFiles.size());
wordsInFiles = wordsInNumFiles(4);
System.out.println("Total words in four files: "+wordsInFiles.size());
printFilesIn("laid");//
System.out.println("\n");
printFilesIn("tree");
//System.out.println("\nList of words that appear in most files: "+wordsInFiles);
/**
*for (int index=0; index < wordsInFiles.size(); index++) {
* System.out.println("Files where "+wordsInFiles.get(index)+" appear:");
* printFilesIn(wordsInFiles.get(index));
*}
*
*for (String key : wordInFilesMap.keySet()) {
* System.out.println("\nWord: "+key+"\tAppears in files: "
* +wordInFilesMap.get(key));
*}
*/
}
}
In the code I've marked down the location of the error by stating HERE!!!
This is the input that I use when testing this program:
cats are funny and cute
dogs are silly
love animals cats and dogs
love birds and cats
These can be found as files at http://www.dukelearntoprogram.com/course3/archives/ProgrammingImprovingGladLibsData.zip

Partition a Set into smaller Subsets and process as batch

I have a continuous running thread in my application, which consists of a HashSet to store all the symbols inside the application. As per the design at the time it was written, inside the thread's while true condition it will iterate the HashSet continuously, and update the database for all the symbols contained inside HashSet.
The maximum number of symbols that might be present inside the HashSet will be around 6000. I don't want to update the DB with all the 6000 symbols at once, but divide this HashSet into different subsets of 500 each (12 sets) and execute each subset individually and have a thread sleep after each subset for 15 minutes, so that I can reduce the pressure on the database.
This is my code (sample code snippet)
How can I partition a set into smaller subsets and process (I have seen the examples for partitioning ArrayList, TreeSet, but didn't find any example related to HashSet)
package com.ubsc.rewji.threads;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;
public class TaskerThread extends Thread {
private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
String symbols[] = new String[] { "One", "Two", "Three", "Four" };
Set<String> allSymbolsSet = Collections
.synchronizedSet(new HashSet<String>(Arrays.asList(symbols)));
public void addsymbols(String commaDelimSymbolsList) {
if (commaDelimSymbolsList != null) {
String[] symAr = commaDelimSymbolsList.split(",");
for (int i = 0; i < symAr.length; i++) {
priorityBlocking.add(symAr[i]);
}
}
}
public void run() {
while (true) {
try {
while (priorityBlocking.peek() != null) {
String symbol = priorityBlocking.poll();
allSymbolsSet.add(symbol);
}
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
while (ite.hasNext()) {
String symbol = ite.next();
if (symbol != null && symbol.trim().length() > 0) {
try {
updateDB(symbol);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateDB(String symbol) {
System.out.println("THE SYMBOL BEING UPDATED IS" + " " + symbol);
}
public static void main(String args[]) {
TaskerThread taskThread = new TaskerThread();
taskThread.start();
String commaDelimSymbolsList = "ONVO,HJI,HYU,SD,F,SDF,ASA,TRET,TRE,JHG,RWE,XCX,WQE,KLJK,XCZ";
taskThread.addsymbols(commaDelimSymbolsList);
}
}
With Guava:
for (List<String> partition : Iterables.partition(yourSet, 500)) {
// ... handle partition ...
}
Or Apache Commons:
for (List<String> partition : ListUtils.partition(yourList, 500)) {
// ... handle partition ...
}
Do something like
private static final int PARTITIONS_COUNT = 12;
List<Set<Type>> theSets = new ArrayList<Set<Type>>(PARTITIONS_COUNT);
for (int i = 0; i < PARTITIONS_COUNT; i++) {
theSets.add(new HashSet<Type>());
}
int index = 0;
for (Type object : originalSet) {
theSets.get(index++ % PARTITIONS_COUNT).add(object);
}
Now you have partitioned the originalSet into 12 other HashSets.
We can use the following approach to divide a Set.
We will get the output as
[a, b]
[c, d]
[e]`
private static List<Set<String>> partitionSet(Set<String> set, int partitionSize)
{
List<Set<String>> list = new ArrayList<>();
int setSize = set.size();
Iterator iterator = set.iterator();
while(iterator.hasNext())
{
Set newSet = new HashSet();
for(int j = 0; j < partitionSize && iterator.hasNext(); j++)
{
String s = (String)iterator.next();
newSet.add(s);
}
list.add(newSet);
}
return list;
}
public static void main(String[] args)
{
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
int size = 2;
List<Set<String>> list = partitionSet(set, 2);
for(int i = 0; i < list.size(); i++)
{
Set<String> s = list.get(i);
System.out.println(s);
}
}
If you are not worried much about space complexity, you can do like this in a clean way :
List<List<T>> partitionList = Lists.partition(new ArrayList<>(inputSet), PARTITION_SIZE);
List<Set<T>> partitionSet = partitionList.stream().map((Function<List<T>, HashSet>) HashSet::new).collect(Collectors.toList());
The Guava solution from #Andrey_chaschev seems the best, but in case it is not possible to use it, I believe the following would help
public static List<Set<String>> partition(Set<String> set, int chunk) {
if(set == null || set.isEmpty() || chunk < 1)
return new ArrayList<>();
List<Set<String>> partitionedList = new ArrayList<>();
double loopsize = Math.ceil((double) set.size() / (double) chunk);
for(int i =0; i < loopsize; i++) {
partitionedList.add(set.stream().skip((long)i * chunk).limit(chunk).collect(Collectors.toSet()));
}
return partitionedList;
}
A very simple way for your actual problem would be to change your code as follows:
Iterator<String> ite = allSymbolsSet.iterator();
System.out.println("=======================");
int i = 500;
while ((--i > 0) && ite.hasNext()) {
A general method would be to use the iterator to take the elements out one by one in a simple loop:
int i = 500;
while ((--i > 0) && ite.hasNext()) {
sublist.add(ite.next());
ite.remove();
}

Categories

Resources