How to find connected friends in a social media using java steam - graph

In a social media, suppose each user is represented like below:
public class User {
private int userId;
private List<User> friendsList;
User(int id) {
this.userID = id;
this.friendsList = new LinkedList<>();
}
void addFriend(User a) {
this.friendsList.add(a);
}
int getUserId() {
return this.userID;
}
List<User> getFriendsList() {
return this.friendsList;
}
}
if A and B are friends(A->B), then A will be added to B's friend list and B will be added to A's friend list.
A.addFriend(B);
B.addFriend(A);
How i can efficiently find two users X and Y are connected by using Java 8 steam methods ?
ie if X->p->q->r->s->Y, then
bool isConnected(User X, User Y) should return true
Here X and Y are connected through common friends p, q, r and s.

You would need a way to keep track of the object that was visited or else you will go in loops.
public bool NodeVisited { get; private set; }
boolean isConnected(User a, User b){
for(final User u : a.getFriendsList()){
if(NodeVisited == false){
NodeVisited = true;
if(u.getUserId() == b.getUserId() || isConnected(u, b)){
return true;
}
}
else continue;
}
return false;
}

The close problem to "Find the shortest way (if any) between 2 points in a labyrinth."
Main idea:
Spread 2 waves from 2 points (or 2 friends) which cover near points (friends)
Remember only(!) previous layers of points (friends) to restrict the future spreading out of the wave in that directions
After each spreading out step check wawes intersection for common points (friends)
Repeat until getting intersections of waves or 1 wave will be stopped:
there are no new directions to spread except in backward directions from the previous step.
P.S.:
The most optimal algorithm involves "several" (depends on data) spots of wave spreading processes.
https://github.com/Dimoniada/FriendsProblem

You don't really have to use streams, but just a simple for-loop and recursion:
boolean isConnected(User a, User b){
for(final User u : a.getFriendsList()){
if(u.getUserId() == b.getUserId() || isConnected(u, b)){
return true;
}
}
return false;
}
If you still want to use streams, you can use this snippet (still uses recursion though):
boolean isConnected(User a, User b){
return a.getFriendsList()
.stream()
.anyMatch(u -> u.getUserId() == b.getUserId() || isConnected(u, b));
}

Related

Breadth first traversal of arbitrary graph with minimal memory

I have an enormous directed graph I need to traverse in search for the shortest path to a specific node from a given starting point. The graph in question does not exist explicitly; the child nodes are determined algorithmically from the parent nodes.
(To give an illustration: imagine a graph of chess positions. Each node is a chess position and its children are all the legal moves from that position.)
So I have a queue for open nodes, and every time I process the next node in the queue I enqueue all of its children. But since the graph can have cycles I also need to maintain a hashset of all visited nodes so I can check if I have visited one before.
This works okay, but since this graph is so large, I run into memory problems. All of the nodes in the queue are also stored in the hashset, which tends to be around 50% of the total number or visited nodes in practice in my case.
Is there some magical way to get rid of this redundancy while keeping the speed of the hashset? (Obviously, I could get rid of the redundancy by NOT hashing and just doing a linear search, but that is out of the question.)
I solved it by writing a class that stores the keys in a list and stores the indices of the keys in a hashtable. The next node "in the queue" is always the the next node in the list until you find what you're looking for or you've traversed the entire graph.
class IndexMap<T>
{
private List<T> values;
private LinkedList<int>[] buckets;
public int Count { get; private set; } = 0;
public IndexMap(int capacity)
{
values = new List<T>(capacity);
buckets = new LinkedList<int>[NextPowerOfTwo(capacity)];
for (int i = 0; i < buckets.Length; ++i)
buckets[i] = new LinkedList<int>();
}
public void Add(T item) //assumes item is not yet in map
{
if (Count == buckets.Length)
ReHash();
int bucketIndex = item.GetHashCode() & (buckets.Length - 1);
buckets[bucketIndex].AddFirst(Count++);
values.Add(item);
}
public bool Contains(T item)
{
int bucketIndex = item.GetHashCode() & (buckets.Length - 1);
foreach(int i in buckets[bucketIndex])
{
if (values[i].Equals(item))
return true;
}
return false;
}
public T this[int index]
{
get => values[index];
}
private void ReHash()
{
LinkedList<int>[] newBuckets = new LinkedList<int>[2 * buckets.Length];
for (int i = 0; i < newBuckets.Length; ++i)
newBuckets[i] = new LinkedList<int>();
for (int i = 0; i < buckets.Length; ++i)
{
foreach (int index in buckets[i])
{
int bucketIndex = values[index].GetHashCode() & (newBuckets.Length - 1);
newBuckets[bucketIndex].AddFirst(index);
}
buckets[i] = null;
}
buckets = newBuckets;
}
private int NextPowerOfTwo(int n)
{
if ((n & n-1) == 0)
return n;
int output = 0;
while (n > output)
{
output <<= 1;
}
return output;
}
}
The old method of maintaining both an array of the open nodes and a hashtable of the visited nodes needed n*(1+a)*size(T) space, where a is the ratio of nodes_in_the_queue over total_nodes_found and size(T) is the size of a node.
This method needs n*(size(T) + size(int)). If your nodes are significantly larger than an int, this can save a lot.

java 8 how to use collection streams to check for presence of an object

I'm new to java 8 programming and would like to know what is the best way to rewrite the below using streams()/lambda's.
class Person {
String name;
int age;
...
}
public boolean checkPersonAboveAge(List<Person> persons, int age) {
for (Person person : persons) {
if (person.age > age) {
return true;
}
}
return false;
}
So far i tried:
public boolean checkPersonAboveAge(List<Person> persons, int age) {
Person p = persons.stream().filter(p -> p.age > age).findAny().orElse(null);
if (p != null) {
return true;
}
return false;
}
I read that with lamdba's the readability of code would improve, but looking at this example either i'm not using this feature right or missing something.
Your current stream attempt does indeed work, but it's an uncommon and not the best way to go about it.
You create an Optional object that you immediately throw away.
The code is not as compact as it can be.
Instead, utilise the anyMatch method which does exactly what you're trying to achieve.
return persons.stream().anyMatch(p -> p.age > age);

Directed Graph Traversal - All paths

Given a directed graph with
A root node
Some leaves nodes
Multiple nodes can be connected to the same node
Cycles can exist
We need to print all the paths from the root node to all the leaves nodes. This is the closest question I got to this problem
Find all paths between two graph nodes
If you actually care about ordering your paths from shortest path to longest path then it would be far better to use a modified A* or Dijkstra Algorithm. With a slight modification the algorithm will return as many of the possible paths as you want in order of shortest path first. So if what you really want are all possible paths ordered from shortest to longest then this is the way to go. The code I suggested above would be much slower than it needs to be if you care about ordering from shortest to longest, not to mention would take up more space then you'd want in order to store every possible path at once.
If you want an A* based implementation capable of returning all paths ordered from the shortest to the longest, the following will accomplish that. It has several advantages. First off it is efficient at sorting from shortest to longest. Also it computes each additional path only when needed, so if you stop early because you dont need every single path you save some processing time. It also reuses data for subsequent paths each time it calculates the next path so it is more efficient. Finally if you find some desired path you can abort early saving some computation time. Overall this should be the most efficient algorithm if you care about sorting by path length.
import java.util.*;
public class AstarSearch {
private final Map<Integer, Set<Neighbor>> adjacency;
private final int destination;
private final NavigableSet<Step> pending = new TreeSet<>();
public AstarSearch(Map<Integer, Set<Neighbor>> adjacency, int source, int destination) {
this.adjacency = adjacency;
this.destination = destination;
this.pending.add(new Step(source, null, 0));
}
public List<Integer> nextShortestPath() {
Step current = this.pending.pollFirst();
while( current != null) {
if( current.getId() == this.destination )
return current.generatePath();
for (Neighbor neighbor : this.adjacency.get(current.id)) {
if(!current.seen(neighbor.getId())) {
final Step nextStep = new Step(neighbor.getId(), current, current.cost + neighbor.cost + predictCost(neighbor.id, this.destination));
this.pending.add(nextStep);
}
}
current = this.pending.pollFirst();
}
return null;
}
protected int predictCost(int source, int destination) {
return 0; //Behaves identical to Dijkstra's algorithm, override to make it A*
}
private static class Step implements Comparable<Step> {
final int id;
final Step parent;
final int cost;
public Step(int id, Step parent, int cost) {
this.id = id;
this.parent = parent;
this.cost = cost;
}
public int getId() {
return id;
}
public Step getParent() {
return parent;
}
public int getCost() {
return cost;
}
public boolean seen(int node) {
if(this.id == node)
return true;
else if(parent == null)
return false;
else
return this.parent.seen(node);
}
public List<Integer> generatePath() {
final List<Integer> path;
if(this.parent != null)
path = this.parent.generatePath();
else
path = new ArrayList<>();
path.add(this.id);
return path;
}
#Override
public int compareTo(Step step) {
if(step == null)
return 1;
if( this.cost != step.cost)
return Integer.compare(this.cost, step.cost);
if( this.id != step.id )
return Integer.compare(this.id, step.id);
if( this.parent != null )
this.parent.compareTo(step.parent);
if(step.parent == null)
return 0;
return -1;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Step step = (Step) o;
return id == step.id &&
cost == step.cost &&
Objects.equals(parent, step.parent);
}
#Override
public int hashCode() {
return Objects.hash(id, parent, cost);
}
}
/*******************************************************
* Everything below here just sets up your adjacency *
* It will just be helpful for you to be able to test *
* It isnt part of the actual A* search algorithm *
********************************************************/
private static class Neighbor {
final int id;
final int cost;
public Neighbor(int id, int cost) {
this.id = id;
this.cost = cost;
}
public int getId() {
return id;
}
public int getCost() {
return cost;
}
}
public static void main(String[] args) {
final Map<Integer, Set<Neighbor>> adjacency = createAdjacency();
final AstarSearch search = new AstarSearch(adjacency, 1, 4);
System.out.println("printing all paths from shortest to longest...");
List<Integer> path = search.nextShortestPath();
while(path != null) {
System.out.println(path);
path = search.nextShortestPath();
}
}
private static Map<Integer, Set<Neighbor>> createAdjacency() {
final Map<Integer, Set<Neighbor>> adjacency = new HashMap<>();
//This sets up the adjacencies. In this case all adjacencies have a cost of 1, but they dont need to.
addAdjacency(adjacency, 1,2,1,5,1); //{1 | 2,5}
addAdjacency(adjacency, 2,1,1,3,1,4,1,5,1); //{2 | 1,3,4,5}
addAdjacency(adjacency, 3,2,1,5,1); //{3 | 2,5}
addAdjacency(adjacency, 4,2,1); //{4 | 2}
addAdjacency(adjacency, 5,1,1,2,1,3,1); //{5 | 1,2,3}
return Collections.unmodifiableMap(adjacency);
}
private static void addAdjacency(Map<Integer, Set<Neighbor>> adjacency, int source, Integer... dests) {
if( dests.length % 2 != 0)
throw new IllegalArgumentException("dests must have an equal number of arguments, each pair is the id and cost for that traversal");
final Set<Neighbor> destinations = new HashSet<>();
for(int i = 0; i < dests.length; i+=2)
destinations.add(new Neighbor(dests[i], dests[i+1]));
adjacency.put(source, Collections.unmodifiableSet(destinations));
}
}
The output from the above code is the following:
[1, 2, 4]
[1, 5, 2, 4]
[1, 5, 3, 2, 4]
Notice that each time you call nextShortestPath() it generates the next shortest path for you on demand. It only calculates the extra steps needed and doesnt traverse any old paths twice. Moreover if you decide you dont need all the paths and end execution early you've saved yourself considerable computation time. You only compute up to the number of paths you need and no more.
Finally it should be noted that the A* and Dijkstra algorithms do have some minor limitations, though I dont think it would effect you. Namely it will not work right on a graph that has negative weights.
Here is a link to JDoodle where you can run the code yourself in the browser and see it working. You can also change around the graph to show it works on other graphs as well: http://jdoodle.com/a/ukx

Reading into collection and retrieving top 5

I was asked this recently in an interview. Application that is reading ticker and trade volume from a live feed,
E.g. AAPL 1000, TWTR 500, MSFT 500, AAPL 500 ...
So, AAPL total volume = 1500 and so on.
I have to read these into a collection and return the top 5 by volume.
I had suggested to use a hash map when storing and then sort or use a Treemap.
Any other way that is more efficient?
Assuming ticker symbol and trade volume are stored together in an instance of some class TickerAndTradeVolume, you could have references to objects contained in multiple data structures.
So a hash map may have ticker symbol as key and TickerAndTradeVolume as value. Then references to TickerAndTradeVolume instances can also be stored in a priority queue. Instances are re-inserted into the PQ on every volume update.
The top n by volume are always available in log(n) amortized time complexity to maintain priorities by trade volume, which is asymptotically faster than sorting via Treemap time and again.
Something like this
Map<String, TickerAndTradeVolume> feed;
PriorityQueue<TickerAndTradeVolume> pq;
class TickerAndTradeVolume implements Comparable<TickerAndTradeVolume> {
private String ticker;
private double volume;
TickerAndTradeVolume(String ticker, double volume) {
this.ticker = ticker;
this.volume = volume;
}
void increaseVolumeBy(double volume) {
this.volume += volume;
}
#Override
public int compareTo(TickerAndTradeVolume that) {
return (int) (that.volume - this.volume);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if(obj instanceof String) {
TickerAndTradeVolume that = (TickerAndTradeVolume) obj;
return this.ticker.equals(that.ticker);
}
return false;
}
}
void addOrUpdateStockVolume(TickerAndTradeVolume tt) {
if(!feed.containsKey(tt.ticker)) {
feed.put(tt.ticker, tt);
pq.add(tt);
}
else {
feed.get(tt.ticker).increaseVolumeBy(tt.volume);
// take out and put back in to trigger heap operations
pq.remove(feed.get(tt.ticker));
pq.add(feed.get(tt.ticker));
}
}
List<TickerAndTradeVolume> getTopMaxFive() {
List<TickerAndTradeVolume> topFive = new ArrayList<TickerAndTradeVolume>(5);
int pqSize = pq.size();
for(int i = 0; i < 5 && i < pqSize; i++) {
// poll() takes from the top of the heap
topFive.add(pq.poll());
}
for(TickerAndTradeVolume tt : topFive) {
// put back what we took out
pq.add(tt);
}
return topFive;
}

Binary Tree and Return root node

..I'm building a binary tree where the root is given and the children are either root-3, root-2 or root-1 (that is, they hold those number of pennies). So 5 would have nodes of 2,3,4, and so on, until the leaves are 0. Here's my method for making such a tree. I don't understand why the method doesn't return the original node, in this case, the value should be 3.
Any guidance would be awesome.
public GameNode buildTree1(GameNode root){
int penn = root.getPennies();
if (penn < 0)
{
return null;
}
else {
root.print();
root.setLeft(buildTree1(new GameNode(penn-1)));
root.setMiddle(buildTree1(new GameNode(penn-2)));
root.setRight(buildTree1(new GameNode(penn-3)));
return root;
}
Get/Set Methods
public void setLeft(GameNode newNode) {
// TODO Auto-generated method stub
left = newNode;
}
Same for setMiddle and setRight;

Resources