Recommend Data structure? multi-map?

Hello everyone.

I'm not sure what data structure I should use for my particular problem.This is whats going to be happening.

I'm writing a SocketServer, its going to be receiving 1000's of strings of random length. Each string is going to have an integer which can be any number, for instance (240). I'm going to parse out that number and it will be the Entity ID. The rest of the string is going to be stored as an "Alert".

So for instance:

Incoming string #1:240 opie.tivlab.raleigh.ibm.com went down at 12:40pm.

Incoming string#2:241 baleve.tivlab.raleigh.ibm.com went down at 4:00pm.

Incoming string#3:240 Error 309830

Incoming string#4:444 Error 20393

The numbers 240, and 241, and 444 are the entityID's.

I want to group the Strings with the EntityID's for instance

I want a list of all the Messages(strings) that had the entityID 240.

so:

if I accessed EntityID 240, I would find the following strings:

EntityID = 240:

1. opie.tivlab.raleigh.ibm.com went down at 12:40pm.

2. Error 309830

If I accessed EntityID 444 I would have:

EntityID = 444

1. Error 20393

I know a map has key/value pairs, can I use the entity ID as the key, and the value's being the rest of the string?

Is what I'm looking for a multimap? can I have 1 key, and have it mapped to several different strings?

Thanks guys!

[1440 byte] By [lokiea] at [2007-11-27 6:41:14]
# 1
A Map with the entity ID as key and a collection of Strings as value? The collection could be ArrayList or something else depending on your requirements.Message was edited by: OleVV
OleVVa at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 2

Thanks for the response.

I was looking at the Java site here:

http://java.sun.com/docs/books/tutorial/collections/interfaces/map.html

and It looks like I can't use just a regular map like this can I?

Map<int,List><String>> Alert = new Map<int,List><String>>();?

But they showed this:

Map<int, List><String>> m

= new HashMap<int, List><String>>();

Message was edited by:

lokie

Message was edited by:

lokie

lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 3
You cannot use int, but Integer or better Long, depending on the range of numbers. I.e. Map< Long, List<String> >
stefan.schulza at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 4

Oh yah! Sorry I'm still learning Java. I've been using C++ for awhile so it will take awhile to break that habit.

So do I need a mutli map or can I just use a map?

I know a map is defiend as linking 1 KEY to exactly 1 VALUE. But does Java know that

Map<Integer, List><String>> m = new HashMap<Integer,List><String>>();

value is a Linked List of Strings? Or does it consider the container List, as 1 value?

I also noticed, they arn't saying:

Map<Integer, List><String>> m = new Map<Integer,List><String>>();

Do you always have to say HashMap, and you can't use Map?

Thanks!

lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 5

Your code should become somewhat like the following:

Map< Integer, List<String> > m = new HashMap< Integer, List<String> >();

...

List<String> lst = m.get(someId);

if (lst == null) {

lst = new ArrayList<String>();

m.put(someId, lst);

}

lst.add(message);

Map and List only are interfaces, where HashMap and ArrayList are implementations of these. There are more implementations available in the collections framework of Java and it depends on your goals, which you take.

The above code includes the creation of a Map that contains lists as values. No List is created at this point!

It further shows how to take the according list from the map that is stored for a specific id or create a new list if none is stored, respectively. Once you have the list, you can add the message. That is, you will have to add a new list object for each id coming in or pick the list to add new messages, if the id has already been treated.

Hope, this is not too confusing an explanation :)

stefan.schulza at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 6

Ahh Excellent example, i'm studying it right now and I have a few questions!

Here is your code:

Map< Integer, List<String> > m = new HashMap< Integer, List<String> >();

...

List<String> lst = m.get(someId);

if (lst == null) {

lst = new ArrayList<String>();

m.put(someId, lst);

}

lst.add(message);

When you say:

List<String>lst = m.get(someId);

I see the interface for Map is:

public interface Map<K,V> {

// Basic operations

V put(K key, V value);

V get(Object key);

Is that "someID" refering to the Integer of the Map? Map<Integer,List><String>> ?

And the return value for that the List object?

So when you assign the return value of m.get(someID) I'm not sure how List<String> lst is processing it.

So if I had the EnityID being 244 and the string is: "server crash".

and I want to place 244 as the "key" for the map, and "server crash" as the first entry in the List<String>

would I do:

Map< Integer, List<String> > m = new HashMap< Integer, List<String> >();

...

String Message = "This server crashed";

List<String> lst = m.get(244);

if (lst == null) {

lst = new ArrayList<String>();

[b] list.add(Message);[/b]

m.put(244, lst);

}

Thanks!

Message was edited by:

lokie

null

Message was edited by:

lokie

Typo

lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 7

> When you say:

> > List<String>lst = m.get(someId);

>

> (...)

> Is that "someID" refering to the Integer of the Map?

Yes.

> Map<Integer,List><String>> ?

> nd the return value for that the List object?

Yes.

> So when you assign the return value of m.get(someID)

> I'm not sure how List<String> lst is processing it.

I am not sure what you mean with processing?

The variable lst will hold a reference to the list stored in the map.

> would I do:

> > Map< Integer, List<String> > m = new HashMap<

> Integer, List<String> >();

> ...

> String Message = "This server crashed";

> List<String> lst = m.get(244);

> if (lst == null) {

>lst = new ArrayList<String>();

> b] list.add(Message);[/b]

>m.put(244, lst);

>

>

Somewhat like that, yes. Of course, you would have the number stored in variable and not hard coded, wouldn't you? And the list.add should be outside the if statement, which only is here to create a new list in case there is no list yet for 244.

I think, the most important information is that you always deal with references to objects and not with objects. So you do not have to put the list back into the map each time, but may use the one you get from the list.

stefan.schulza at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 8

Thanks the the help its going pretty good now that you started me out.

The problem i'm having now is printing out the Key along with all the messages...

It skips the first element but everything else is working!

Because Maps don't support iterators I soon found out, I put all the keys in a set which does support iteerators...here is my code:

package alert;

import java.util.List;

import java.util.HashMap;

import java.util.Map;

import java.util.ArrayList;

import java.util.Set;

import java.util.Iterator;

public class Message {

Integer entityID;

String message;

//constructor

Message(Integer entityID, String message)

{

this.entityID = entityID;

this.message = message;

}

//no param construct

Message()

{

entityID = new Integer(0);

message = "";

}

//print******ISSUE IS IN HERE*********-

void print(Map<Integer, List><String> > hashM)

{

//want to print out the Key and all the Messages

//associated with that key

Set keys = hashM.keySet();// The set of keys in the map.

Iterator keyIter = keys.iterator();

System.out.println("The map contains the following associations:");

while (keyIter.hasNext()) {

Object key = keyIter.next(); // Get the next key.

Object value = hashM.get(key); // Get the value for that key.

System.out.println( "(" + key + "," + value + ")" );

}

}

void Input(Map<Integer, List><String>> mapAlert, Integer entityID, String msg)

{

//getting the position of the List by EntityID if avaiable

List<String> Alert = mapAlert.get(entityID);

//checking to see if there is a unique Key already in the Map.

if (Alert == null)

{

//if there isnt a key in the map, add a new key, and a new List mapping

//to the key EntityID;

Alert = new ArrayList<String>();

mapAlert.put(entityID, Alert);

}

else

{

//adding message to List

Alert.add(msg);

}

}

}

//-Main function

package alert;

import java.util.List;

import java.util.HashMap;

import java.util.Map;

public class Alert {

public static void main(String [] args)

{

Map<Integer, List><String>> AlertMap = new HashMap<Integer, List><String>>();

String message = "This is a test1";

String message2 = "This is another test2";

String message3 = "This is another test3";

String message4 = "This is for key(222) test1";

String message5 = "This is for key(222) test2";

String message6 = "This is for key(222) test3";

Integer entityID = new Integer(333);

Integer entityID2 = new Integer(222);

Message testMessage = new Message();

//manually inserting strings into Map.

//For ID: 333

testMessage.Input(AlertMap,entityID, message);

testMessage.Input(AlertMap,entityID, message2);

testMessage.Input(AlertMap,entityID, message3);

//For ID: 222

testMessage.Input(AlertMap,entityID2, message4);

testMessage.Input(AlertMap,entityID2, message5);

testMessage.Input(AlertMap,entityID2, message6);

testMessage.print(AlertMap);

}

}

//OUTPUT:

The map contains the following associations:

(222,[This is for key(222) test2, This is for key(222) test3])

(333,[This is another test2, This is another test3])

lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 9
N/M I fixed it!During the Add function I added an if() else, in the if I should have also added the new string, after creating the new list! it works great now!XD
lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 10

That's why I said to put the add outside the if ;)

Btw., for looping on a Map you can use different approaches. As you recognized, the map gives you a reference to the key's set. It also gives you a handle on the set of entries, which allows you to use the for-each loop instead iterators (like does the key's set):for (Map.Entry< Integer, List<String> > entry : map.entrySet()) {

Integer id = entry.getKey();

List<String> msgs = entry.getValue();

...

}

Further, you should also loop over the messages to print them, rather than printing the List directly. And, when you definitely want to use the iterator, you should use it generic as Iterator<Integer>. And, when getting the value from the map, you have definitely more information on it than it being an Object.

Good luck.

stefan.schulza at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 11

Your way is alot nicer than mine :D

Hm...i'm not sure how else I would print out the contents of the list without just using how I did it...

Do you know off hand how I can print the messages, rather than the list directly?

Maybe that will also fix my formatting issue i'm running into, its printing the contents of the map like this:

Entity ID: 333

[message1,message2....,...message x]

lokiea at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...
# 12

> Hm...i'm not sure how else I would print out the

> contents of the list without just using how I did

> it...

> Do you know off hand how I can print the messages,

> rather than the list directly?

Erm ... you could loop over the list and print each entry?

stefan.schulza at 2007-7-12 18:10:46 > top of Java-index,Core,Core APIs...