What is the Java 8 way to pull an object from a set? - java-8

I'd like to pull an item out of a set, and keep it, based on a predicate. It sure seems like this should be possible, but I can't find a way to prevent going thru the list twice. Such an operation could be used to 'pop' an object based on a dynamic priority.
Perhaps I should stick with an iterator.
Here's an example:
import org.junit.Test;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class RemoveAndUse {
class A {
int x;
A(int x) { this.x = x;}
}
class B {
int y;
B(int y) { this.y = y;}
}
#Test
public void removeHappyPath() {
Set<A> aList = new HashSet<>(Arrays.asList(new A(1), new A(2), new A(3)));
B b = new B(2);
// remove and keep an A that matches b
A found = aList.stream()
.filter( a -> a.x == b.y )
.findAny().get();
aList.removeIf( a -> a.x == b.y);
// or: aList.remove(found);
assert(!aList.contains(found));
assert(found.x == b.y);
}
}
Any other ideas?

A found;
for (Iterator<A> it = aList.iterator();it.hasNext();) {
A a = it.next();
if (a.x == b.y) {
found = a;
it.remove();
break;
}
}
O(n) is guaranteed;

Related

Functional/Stream programming for the graph problem "Reconstruct Itinerary"

I am trying to solve the reconstruct itinerary problem (https://leetcode.com/problems/reconstruct-itinerary/) in Scala using functional approach. Java solution works but Scala doesn't. One reason I found out was the hashmap is being updated and every iteration has the latest hashmap (even when popping from recursion) which is weird.
Here is the solution in Java:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
public class Solution1 {
private void dfg(Map<String, PriorityQueue<String>> adj, LinkedList<String> result, String vertex){
PriorityQueue<String> pq = adj.get(vertex);
while (pq!=null && !pq.isEmpty()){
System.out.println("Before :"+adj.get(vertex));
String v = pq.poll();
System.out.println("After :"+ adj.get(vertex));
dfg(adj,result,v);
}
result.addFirst(vertex);
}
public List<String> findItinerary(List<List<String>> tickets){
Map<String,PriorityQueue<String>> adj = new HashMap<>();
for(List<String> ticket: tickets){
adj.putIfAbsent(ticket.get(0),new PriorityQueue<>());
adj.get(ticket.get(0)).add(ticket.get(1));
}
LinkedList<String> result = new LinkedList<>();
dfg(adj,result,"JFK");
//not reverse yet
return result;
}
public static void main(String[] args){
List<List<String>> tickets = new ArrayList<>();
List t1= new ArrayList();
t1.add("JFK");
t1.add("SFO");
tickets.add(t1);
List t2= new ArrayList();
t2.add("JFK");
t2.add("ATL");
tickets.add(t2);
List t3= new ArrayList();
t3.add("SFO");
t3.add("ATL");
tickets.add(t3);
List t4= new ArrayList();
t4.add("ATL");
t4.add("JFK");
tickets.add(t4);
List t5= new ArrayList();
t5.add("ATL");
t5.add("SFO");
tickets.add(t5);
System.out.println();
Solution1 s1 = new Solution1();
List<String> finalRes = s1.findItinerary(tickets);
for(String model : finalRes) {
System.out.print(model + " ");
}
}
}
Here is my solution in Scala which is not working:
package graph
class Itinerary {
}
case class Step(g: Map[String,List[String]],sort: List[String]=List())
object Solution {
def main(arr: Array[String]) = {
val tickets = List(List("JFK","SFO"),List("JFK","ATL"),List("SFO","ATL"),List("ATL","JFK"),List("ATL","SFO"))
println(findItinerary(tickets))
}
def findItinerary(tickets: List[List[String]]): List[String] = {
val g = tickets.foldLeft(Map[String,List[String]]())((m,t)=>{
val key=t(0)
val value= t(1)
m + (key->(m.getOrElse(key,Nil) :+ value).sorted)
})
println(g)
// g.keys.foldLeft(Step())((s,n)=> dfs(n,g,s)).sort.toList
dfs("JFK",Step(g)).sort.toList
}
def dfs(vertex: String,step: Step): Step = {
println("Input vertex " + vertex)
println("Input map "+ step.g)
val updatedStep= step.g.getOrElse(vertex,Nil).foldLeft(step) ((s,n)=>{
//println("Processing "+n+" of vertex "+vertex)
//delete link
val newG = step.g + (vertex->step.g.getOrElse(vertex,Nil).filter(v=>v!=n))
// println(newG)
dfs(n,step.copy(g=newG))
})
println("adding vertex to result "+vertex)
updatedStep.copy(sort = updatedStep.sort:+vertex)
}
}
Scala is sometimes approached as a "better" Java, but that's really very limiting. If you can get into the FP mindset, and study the Standard Library, you'll find that it's a whole new world.
def findItinerary(tickets: List[List[String]]): List[String] = {
def loop(from : String
,jump : Map[String,List[String]]
,acc : List[String]) : List[String] = jump.get(from) match {
case None => if (jump.isEmpty) from::acc else Nil
case Some(next::Nil) => loop(next, jump - from, from::acc)
case Some(nLst) =>
nLst.view.map{ next =>
loop(next, jump+(from->(nLst diff next::Nil)), from::acc)
}.find(_.lengthIs > 0).getOrElse(Nil)
}
loop("JFK"
,tickets.groupMap(_(0))(_(1)).map(kv => kv._1 -> kv._2.sorted)
,Nil).reverse
}
I am going to be honest that I didn't look through your code to see where the problem was. But, I got caught by the problem and decided to give it a go; here is the code:
(hope my code helps you)
type Airport = String // Refined 3 upper case letters.
final case class AirlineTiket(from: Airport, to: Airport)
object ReconstructItinerary {
// I am using cats NonEmptyList to improve type safety, but you can easily remove it from the code.
private final case class State(
currentAirport: Airport,
availableDestinations: Map[Airport, NonEmptyList[Airport]],
solution: List[Airport]
)
def apply(tickets: List[AirlineTiket])(start: Airport): Option[List[Airport]] = {
#annotation.tailrec
def loop(currentState: State, checkpoints: List[State]): Option[List[Airport]] = {
if (currentState.availableDestinations.isEmpty) {
// We used all the tickets, so we can return this solution.
Some((currentState.currentAirport :: currentState.solution).reverse)
} else {
val State(currentAirport, availableDestinations, solution) = currentState
availableDestinations.get(currentAirport) match {
case None =>
// We got into nowhere, lets see if we can return to a previous state...
checkpoints match {
case checkpoint :: remaining =>
// If we can return from there
loop(currentState = checkpoint, checkpoints = remaining)
case Nil =>
// If we can't, then we can say that there is no solution.
None
}
case Some(NonEmptyList(destination, Nil)) =>
// If from the current airport we can only travel to one destination, we will just follow that.
loop(
currentState = State(
currentAirport = destination,
availableDestinations - currentAirport,
currentAirport :: solution
),
checkpoints
)
case Some(NonEmptyList(destination, destinations # head :: tail)) =>
// If we can travel to more than one destination, we are going to try all in order.
val newCheckpoints = destinations.map { altDestination =>
val newDestinations = NonEmptyList(head = destination, tail = destinations.filterNot(_ == altDestination))
State(
currentAirport = altDestination,
availableDestinations.updated(key = currentAirport, value = newDestinations),
currentAirport :: solution
)
}
loop(
currentState = State(
currentAirport = destination,
availableDestinations.updated(key = currentAirport, value = NonEmptyList(head, tail)),
currentAirport :: solution
),
newCheckpoints ::: checkpoints
)
}
}
}
val availableDestinations = tickets.groupByNel(_.from).view.mapValues(_.map(_.to).sorted).toMap
loop(
currentState = State(
currentAirport = start,
availableDestinations,
solution = List.empty
),
checkpoints = List.empty
)
}
}
You can see the code running here.

List as an object field - how to handle it via Stream (Java 8)?

There is a Waybill object that has a Set<Packing> field, the Packing object has a PRICE field.
I get a List<Waybill>.
Need to calculate the total cost of all Packing from the entire List<Waybill>.
How it competently to make through Stream?
Thank you.
class Waybill {
Set<Packing> setOfPacking;
}
class Packing {
int PRICE;
}
List<Waybill> allWaybills = ...
This worked for me:
double total = allWaybills.stream()
.flatMap(waybill -> waybill.setOfPacking.stream())
.mapToInt(packing -> packing.PRICE)
.sum();
I think it is easier to reason about because there aren't any multi-level stream operations.
I would be interested to see how to use flatMapToInt to replace both the flatMap and map operations with one operation without making it multi-level.
Here is a test program:
import java.util.Set;
import java.util.List;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class HelloWorld
{
public static class Packing
{
public int PRICE = 0;
}
public static class Waybill
{
public Set<Packing> setOfPacking = new HashSet<Packing>();
}
public static void main(String []args){
List<Waybill> allWaybills = new ArrayList<Waybill>();
Waybill w1 = new Waybill();
Packing p1 = new Packing(); p1.PRICE = 1; w1.setOfPacking.add(p1);
Packing p2 = new Packing(); p2.PRICE = 2; w1.setOfPacking.add(p2);
allWaybills.add(w1);
Waybill w2 = new Waybill();
Packing p3 = new Packing(); p3.PRICE = 3; w2.setOfPacking.add(p3);
Packing p4 = new Packing(); p4.PRICE = 4; w2.setOfPacking.add(p4);
allWaybills.add(w2);
double total = allWaybills.stream()
.flatMap(waybill -> waybill.setOfPacking.stream())
.mapToInt(packing -> packing.PRICE)
.sum();
System.out.println("total = "+total);
}
}
import java.util.stream.*
List<Waybill> allWaybills = ...
int totalCost = allWaybills
.stream()
.mapToInt(w -> w.setOfPacking
.stream()
.mapToInt(p -> p.PRICE)
.sum()
)
.sum();

how to get multi properties's mean values using java8 stream?

there's one Object
#Data
class ScoreInfo{
String id;
float cove_score;
float theam_score;
float content_score;
float teach_score;
Date create_date;
ScoreInfoP scoreInfoP;
}
and ScoreInfoP is :
#Data
class ScoreInfoP{
String stream_sn;
String anchor_id;
String create_by;
}
sourceList is a list of ScoreInfo,I want to get cove_score,theam_score,content_score,teach_score's mean values,group by scoreInfoP property and return four mean values for each of these properties.
I can get only one mean value using such code:
Map<ScoreInfoP, Double> meanForCoveScore = sourceList.stream().collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP,
Collectors.averagingDouble(ScoreInfo::getCove_score)));
I want to learn how to get four mean values using java8 or any easier way you suggest achieving this.
Waiting here for your generous help.
There isn't anything build-in for this, but it's not that complicated to build a custom Collector for that...
Map<String, List<Float>> result = Arrays.asList(first, second)
.stream()
.collect(Collectors.groupingBy(
x -> x.getScoreInfoP().getAnchorId(),
Collector.of(
() -> new float[5],
(a, x) -> {
a[0] += x.getCoveScore();
a[1] += x.getTheamScore();
a[2] += x.getTeachScore();
a[3] += x.getContentScore();
a[4]++;
},
(left, right) -> {
for (int i = 0; i < 4; ++i) {
left[i] += right[i];
}
return left;
}, x -> Arrays.asList(x[0] / x[4], x[1] / x[4], x[2] / x[4], x[3] / x[4]))
));
System.out.println(result);
I actually groupBy here on ScoreInfoP#anchorId; but you can do it on ScoreInfoP - for that you need to change x -> x.getScoreInfoP().getAnchorId() to x -> x.getScoreInfoP(). But obviously ScoreInfoP needs to override hashCode and equals.
As I said in the comment you should use a proper result class.
class ScoreInfoAverage {
private float cove_score;
private float theam_score;
private float content_score;
private float teach_score;
// ctor, getter, setter
}
Then you can use a custom Collector:
public static Collector<ScoreInfo, ?, ScoreInfoAverage> scoreInfoToAverage() {
class ScoreInfoAccumulator {
private DoubleSummaryStatistics cove_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics theam_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics content_score = new DoubleSummaryStatistics();
private DoubleSummaryStatistics teach_score = new DoubleSummaryStatistics();
public void add(ScoreInfo si) {
cove_score.accept(si.cove_score);
theam_score.accept(si.theam_score);
content_score.accept(si.content_score);
teach_score.accept(si.teach_score);
}
public ScoreInfoAccumulator combine(ScoreInfoAccumulator sia) {
cove_score.combine(sia.cove_score);
theam_score.combine(sia.theam_score);
content_score.combine(sia.content_score);
teach_score.combine(sia.teach_score);
return this;
}
public ScoreInfoAverage average() {
return new ScoreInfoAverage((float) cove_score.getAverage(),
(float) theam_score.getAverage(), (float) content_score.getAverage(),
(float) teach_score.getAverage());
}
}
return Collector.of(ScoreInfoAccumulator::new, ScoreInfoAccumulator::add,
ScoreInfoAccumulator::combine, ScoreInfoAccumulator::average);
}
Last but not least you add your Collector to the downstream:
Map<ScoreInfoP, ScoreInfoAverage> collect = scoreInfos.stream()
.collect(Collectors.groupingBy(ScoreInfo::getScoreInfoP, scoreInfoToAverage()));

How to find the address where width and height are stored inside an mp4 file?

I need to find the addresses where the width and height are stored, but the IUT version of the standard don't give a clear definition of the file format.
What I found so far... :
Both values are stored in "a QuickTime float". I couldn't find the format, but it seems it use two 16-bits integer: a signed one followed by an unsigned one.
Unlike many file format, there are no fixed position, so it is file specific. It depend on the TrackHeaderBox address.
What I desperatly need :
A clear canonical answer describing the places to find only those kind of information. I don't want answers only referring to third party libraries (unless they are written in proper JavaScript). Some pseudo C like structures can help.
There is no fixed position. You need to parse into the file. Please check this Java example.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
public class GetHeight {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(new File(args[0]));
GetHeight ps = new GetHeight();
ps.find(fis);
}
byte[] lastTkhd;
private void find(InputStream fis) throws IOException {
while (fis.available() > 0) {
byte[] header = new byte[8];
fis.read(header);
long size = readUint32(header, 0);
String type = new String(header, 4, 4, "ISO-8859-1");
if (containers.contains(type)) {
find(fis);
} else {
if (type.equals("tkhd")) {
lastTkhd = new byte[(int) (size - 8)];
fis.read(lastTkhd);
} else {
if (type.equals("hdlr")) {
byte[] hdlr = new byte[(int) (size - 8)];
fis.read(hdlr);
if (hdlr[8] == 0x76 && hdlr[9] == 0x69 && hdlr[10] == 0x64 && hdlr[11] == 0x65) {
System.out.println("Video Track Header identified");
System.out.println("width: " + readFixedPoint1616(lastTkhd, lastTkhd.length - 8));
System.out.println("height: " + readFixedPoint1616(lastTkhd, lastTkhd.length - 4));
System.exit(1);
}
} else {
fis.skip(size - 8);
}
}
}
}
}
public static long readUint32(byte[] b, int s) {
long result = 0;
result |= ((b[s + 0] << 24) & 0xFF000000);
result |= ((b[s + 1] << 16) & 0xFF0000);
result |= ((b[s + 2] << 8) & 0xFF00);
result |= ((b[s + 3]) & 0xFF);
return result;
}
public static double readFixedPoint1616(byte[] b, int s) {
return ((double) readUint32(b, s)) / 65536;
}
List<String> containers = Arrays.asList(
"moov",
"mdia",
"trak"
);
}

why Array Index Out Of Bound Exception while re arranging doc file paragraph?

Here is a code snippet. Its giving arrayindexoutofboundexception. dont know why ?
import java.io.File;
import java.io.FileInputStream;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xslf.usermodel.XSLFTextParagraph;
public class wordcount
{
public static void main(String[] args) throws Exception
{
File file = new File("E:\\myFiles\\abc.doc");
FileInputStream fis=new FileInputStream(file.getAbsolutePath());
HWPFDocument document=new HWPFDocument(fis);
WordExtractor extractor = new WordExtractor(document);
String [] fileData = extractor.getParagraphText();
for (int i = 0; i < fileData.length; i++)
{
// System.out.println(fileData[i].toString());
String[] paraword = fileData[i].toString().split(" ");
// out.println(paraword.length);
if(paraword[i].length() == 0 )
{
System.out.println("\n");
}
else if(paraword[i].length() > 0 && paraword[i].length() < 12)
{
for(int k=0 ; k < paraword[i].length()-1 ; k++)
{
System.out.println(paraword[k].toString());
}
}
else if(paraword[i].length() >= 12 )
{
for(int k=0 ; k < 12 ; k++)
{
System.out.println(paraword[k].toString());
}
}
System.out.println("\n");
}
}
}
This is the image of the abc.doc file
Note : Expected output will be printed on java console.
and the output will contain 12 words in each line. But after executing first line the error occurs.
Any help would be appreciated
TIA
Honestly, I'm not familiar with the apache.org API, but just by looking at your logic it looks like you want to replace every instance of:
paraword[i].length()
with:
paraword.length
Because it looks like you want to check how many words are in the paragraph and not how long the first word of the paragraph is. Correct me if I'm wrong, but I think that will fix you up.
Here is the correct code snippet
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
public class ExtractWordDocument
{
public String myString() throws IOException
{
File file = new File("PATH FOR THE .doc FILE");
FileInputStream fis=new FileInputStream(file.getAbsolutePath());
HWPFDocument document=new HWPFDocument(fis);
WordExtractor extractor = new WordExtractor(document);
String [] fileData = extractor.getParagraphText();
ArrayList<Object> EntireDoc = new ArrayList<>();
for (int i = 0; i < fileData.length; i++)
{
String[] paraword = fileData[i].toString().split("\\s+");
if(paraword.length == 0 )
{EntireDoc.add("\n");}
else if(paraword.length > 0 && paraword.length < 12)
{
for(int k=0 ; k < paraword.length ; k++)
{EntireDoc.add(paraword[k].toString()+" ");}
}
else if(paraword.length > 12 )
{
java.util.List<String> arrAsList = Arrays.asList(paraword);
String formatedString = arrAsList.toString()
.replace(",", "") //remove the commas
.replace("[", "") //remove the right bracket
.replace("]", ""); //remove the left bracket
StringBuilder sb = new StringBuilder(formatedString);
int i1 = 0;
while ((i1 = sb.indexOf(" ", i1 + 75)) != -1)
{sb.replace(i1, i1 + 1, "\n");}
EntireDoc.add(sb.toString());
}
EntireDoc.add("\n");
}
String formatedString = EntireDoc.toString()
.replace(",", "") //remove the commas
.replace("[", "") //remove the right bracket
.replace("]", ""); //remove the left bracket
return formatedString;
}
public static void main(String[] args)
{
try{
System.out.print(new ExtractWordDocument().myString());
}
catch(IOException ioe){System.out.print(ioe);}
}
}
Note : This code will not print 12 words in each line but 75 charecters in each line.

Resources