Data structure: Two maps that point to the same value - data-structures

I am looking for a data structure where multiple maps point to the same value
For example:
We have an object A
We have two maps Map1 and Map2
var map1 = {
objectA.attribute1: objectA
}
var map2 = {
objectA.attribute2: objectA
}
Now, if I delete the object from one map, it should also delete it in the other map.
var attribute1 = objectA.attribute1
var attribute2 = objectA.attribute2
delete map1[attribute1]
map2[attribute2] === null
In other words, there are multiple ways to look up an object but once it is deleted all the look ups are gone as well.
An alternative way to look at this problem might be:
This is a SQL like row based data structure.
We have an array of objects. Certain attributes in the object can be looked up in a map-like fashion. And the object can be deleted by any of the attributes.
Is there a data structure that will help me do this?

you should use a two way hash. one map keys to object the other maps objects to keys.
to add an object by key1,key2,...keyN :
insert the object to the first map by the list of keys and add the list of keys to the map by the object, where usually you would use a hash of the object for this purpose.
var map_by_key = { 'key1' : objectA , 'key2' : objectA , ... 'keyN' : objectA }
var map_by_object = { objectA_hash : [ 'key1' , 'key2' , ... , 'keyN' ] }
to remove an object by key:
get the object by the key from the first map then get the list of keys from object hash from the second map. removing all keys from the first map and lastly remove the key from the second map.

Related

Java-8 - sort keys of Map

I have this Java Map:
Map<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject>
....
public enum ScheduleAbsenceHeaderHistoryTypeEnum {
ADDITIONAL_HOURS("ADDITIONAL_HOURS"),
HOLIDAY("HOLIDAY"),
REMAINING_HOLIDAY_HOURS("REMAINING_HOLIDAY_HOURS"),
REMAINING_HOLIDAY_DAYS("REMAINING_HOLIDAY_DAYS"),
TRANSFER_HOLIDAY("TRANSFER_HOLIDAY"),
INCREMENT_HOLIDAY("INCREMENT_HOLIDAY"),
..
and I will sort the keys of the map alphabetically.
Is there a possibility to do this in a simple way?
You can create a map sorted by the enum’s name like
Map<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject> map
= new TreeMap<>(Comparator.comparing(Enum::name));
This uses the constant name as declared in the enum class, e.g.
enum ScheduleAbsenceHeaderHistoryTypeEnum {
ADDITIONAL_HOURS, HOLIDAY, REMAINING_HOLIDAY_HOURS,
REMAINING_HOLIDAY_DAYS, TRANSFER_HOLIDAY, INCREMENT_HOLIDAY,
}
There is no need to specify that name manually.
But if you have a property that might be different from the name, you may use
Map<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject> map
=new TreeMap<>(Comparator.comparing(ScheduleAbsenceHeaderHistoryTypeEnum::getProperty));
to sort by that specific property.
Given Map<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject> map:
map.keySet().stream()
.sorted(Comparator.comparing(ScheduleAbsenceHeaderHistoryTypeEnum::getName))
.collect(Collectors.toList());
will produce a sorted List<ScheduleAbsenceHeaderHistoryTypeEnum>.
Edit:
If you like to get a Map which has its keys sorted while you put elements into it use something like this:
SortedMap<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject> map =
new TreeMap<ScheduleAbsenceHeaderHistoryTypeEnum, ValueObject>(comparing(ScheduleAbsenceHeaderHistoryTypeEnum::getName)) {{
put(HOLIDAY, null);
put(REMAINING_HOLIDAY_DAYS, null);
put(TRANSFER_HOLIDAY, null);
put(INCREMENT_HOLIDAY, null);
put(ADDITIONAL_HOURS, null);
}};
The statement:
map.keySet().forEach(System.out::println);
will produce the following output:
ADDITIONAL_HOURS
HOLIDAY
INCREMENT_HOLIDAY
REMAINING_HOLIDAY_DAYS
TRANSFER_HOLIDAY

linq select items where property of items in list not in properties of items in another list

I have two lists of 2 different types of classes. I want to select all of the items in the first list that have a property (we'll call it name) that do not have coresponding objects with same name in another list.
For example if I have a list of Age items (joe, 4), (marry,5), (ed,2)
and another list of relation items (joe,father), (ed,brother)
I want to end up with a resulting list of (marry,5)
I was not sure if "except" was somehow used here.
Given two arrays (I'm using anonymous types here, but it's the same deal with proper classes) of different types, you're going to need to extract the excepted 'key' first. In this case the 'key' is the Name property.
//Setup
var ageItems = new [] { new {Name = "Joe", Age=4}, new {Name = "Marry", Age=5}, new {Name="Ed", Age=2} };
var relationItems = new [] { new {Name="Joe", Rel = "Father"}, new {Name="Ed", Rel="Brother"} };
//Get the names
var exceptedNames = ageItems.Select (a => a.Name).Except(relationItems.Select (r => r.Name));
//At this point, we have an `IEnumerable` containing 'Marry', we need to get the instances
var exceptedItems = ageItems.Where(a => exceptedNames.Contains(a.Name));
Of course, being LINQ, you can whack it all into one call:
var exceptedItems = ageItems.Where (a => ageItems.Select (b => b.Name).Except(relationItems.Select (r => r.Name)).Contains(a.Name));
You can't use the .Except overload that takes an IEqualityComparer instance as your classes differ, and IEqualityComparer can only compare two items of the same type, hence we have to generalise and pull out the same fields.

How to remove from an List Object in c#

I have an Action method in my controller which returns a List Object
Public ActionResult GetCats(long Id,string strsortorder,string dltIds)
{
var Result=objrepo.GetCats(Id);//this method returns me List of Result
}
My array looks like this:
var Result=[{CatId:1015,CatName:Abc},{CatId:1016,CatName:Acd},
{CatId:1017,CatName:Adf},{CatId:1018,CatName:CDdf},{CatId:1019,CatName:asdas},
{CatId:1020,CatName:Abc},{CatId:1021,CatName:Abc},{CatId:1022,CatName:Abc},
{CatId:1023,CatName:Abc},{CatId:1024,CatName:Abc}]
What I want to do is:
Using two more parameters in my Action Method "strsortorder" and "dltIds"
that have a list of ids like this:
strsortorder="1021,1015,1016,1019,1022";
dltIds="1017,1018,1020";
From this the "Result" returned from my method , I want to remove the records which are in "dltids" and the remaining array should be sorted in the order which I have in "strsortorder";
In the end the new object should look like this:
var NewResult=[{CatId:1021,CatName:Abc},{CatId:1015,CatName:Abc},
{CatId:1016,CatName:Acd},{CatId:1019,CatName:asdas},{CatId:1022,CatName:Abc},
{CatId:1023,CatName:Abc},{CatId:1024,CatName:Abc}]
Can any one help me in acheiving this in linq or any other way?
I want to avoid any type of loop or froeach here for max extent, I know it can be done by looping but I want to avoid this since the result can sometimes contain large amounts of data.
I realized you can use an ArrayList instead of a Dictionary and it would be faster. I think Dictionary is clear how it works but here is the "better" implementation using array list:
var excludeList = dltIds.Split(",".ToCharArray());
ArrayList sortList = new ArrayList(strsortorder.Split(",".ToCharArray()));
var NewResult =
Result.Where(item => ! excludeList.Contains(item.CatId.ToString()))
.OrderBy(item => {
if (sortList.Contains(item.CatId.ToString()))
return sortList.IndexOf(item.CatId.ToString());
return sortList.Count;
});
Original answer below:
Public ActionResult GetCats(long Id,string strsortorder,string dltIds)
{
var Result=objrepo.GetCats(Id);//this method returns me List of Result
var excludeList = dltIds.Split(",".ToCharArray());
int orderCount = 0; // used in the closure creating the Dictionary below
var sortList = strsortorder.Split(",".ToCharArray())
.ToDictionary(x => x,x => orderCount++);
// filter
var NewResult =
Result.Where(item => ! excludeList.Contains(item.CatId.ToString()))
.OrderBy(item => {
if (sortList.ContainsKey(item.CatId.ToString()))
return sortList[item.CatId.ToString()];
return sortList.Count();
});
}
How this works:
First I create lists out of your comma separated exclude list using split.
This I create a dictionary with the key being the ordering ID and the value being an integer that goes up by one.
For the filtering I look to see if an item is in the exclude array before I continue processing the item.
I then do a sort on matching against the key and the dictionary and returning the value -- this will sort things in the order of the list since I incremented a counter when creating the values. If an item is not in the dictionary I return one more than the maximum value in the dictionary which must be the count of the items. (I could have used the current value of orderCount instead.)
Questions?

Any way to add a property using linq?

So I have this list, it returns an ID and a thumbnail. ex. List<PersonPicture>
and I have this list, List<Person> which has a property named "picture" in it.
Is there anyway that I can merge this two properties and add the List<PersonPicture> to the property named "picture" in it and base this via the ID since they have the same?
Any help would be appreciated.
You can use an anonymous object for this, below an example:
List<PersonPicture> pictures = LoadPictures();
List<Person> persons = LoadPersons();
var result = persons.Select(pers => new
{
Id = pers.Id,
Name = pers.Name,
Picture = pictures.Where(pic => pic.PersId == pers.Id)
.FirstOrDefault()
.Thumbnail
};
Another solution is to use a Join:
var result = persons.Join(pictures,
pers => pers.Id,
pic => pic.PersId,
(pers, pic) => {
return new
{
Id = pers.Id,
Name = pers.Name,
Picture = pic.Thumbnail
};
});
LINQ isn't quite designed for modifying existing collections like this, but you can do it:
foreach (tup in people
.Join(
picture,
person => person.ID,
picture => picture.ID,
Tuple.Create
))
{
tup.Item1.Picture = tup.Item2;
}
EDIT: Note that this will produce unpredictable results if a person has more than one picture. Is this a possibility, and how should it be dealt with?
You could either use a Join or the Zip operator in linq. These links will take you to questions about the syntax of using both of them. Basically the Join just adds the two lists together based on a key just like in SQL and the Zip merges the two lists by matching the position of each element in each list..
You want to join the two lists based on a shared key -- the ID.
Basically, you want to use the Join operator in LINQ to find pairs of Person and PersonPicture that match the same ID:
persons.Join(pictures, // join these two lists
person => person.Id, // extract key from person
personPicture => personPicture.PersonId, // extract key from picture
(person, personPicture) => ??? // do something with each matching pair
The question you now face is what to do with each matching pair; Join lets you supply a delegate that takes a matching pair and returns something else, and the result of the Join operation will be a list of those 'something else's produced from each of the matching pairs.
Your problem is that you want to take each pair and do something with it -- specifically, you want to copy the picture from the PersonPicture object to the Person object. Since LINQ is all about finding data but not modifying it, this is not trivial.
You can do this in two ways. One is to create a temporary object from each pair, and then iterate over that and do your thing:
var pairs = persons.Join(pictures,
person => person.Id,
personPicture => personPicture.PersonId,
(person, personPicture) => new { person, personPicture };
foreach (var pair in pairs)
pair.person.Picture = pair.personPicture.Thumbnail;
(You can use a Tuple instead of a temporary object, as was suggested in another answer).
This works, but seems clumsy because of the temporary object (be it an anonymous object or a tuple).
Alternatively, you can do the assignment right inside the delegate, and return the Person object itself, since you're done with the PersonPicture object:
var personsWithPicturesPopulated = persons.Join(pictures,
person => person.Id,
personPicture => personPicture.PersonId,
(person, personPicture) => {
person.Picture = personPicture.Thumbnail;
return person;
});
This has the added bonus of giving you the list of persons for which you found a match in the personPictures list, omitting the ones without a match; this is sometimes exactly what you need (and other times it isn't, in which case you can discard the result of the join).

Update entity columns iterating through col list using LINQ

I can get column list from the table using LINQ like this:
OrderDataContext ctx = new OrderDataContext();
var cols = ctx.Mapping.MappingSource
.GetModel( typeof( OrderDataContext ) )
.GetMetaType( typeof( ProductInformation ) )
.DataMembers;
This gives me the list of columns, so I can do this:
foreach ( var col in cols )
{
// Get the value of this column from another table
GetPositionForThisField( col.Name );
}
So this all works, I can iterate through column list and pull the values for those columns from an another table (since the column names are the keys in that another table), so I don't have to do switch....or lot of if...then...
Now the question:
After I get these values, how do I populate the entity in order to save it back? I would normally go like this:
ProductInformation info = new ProductInformation();
info.SomeField1 = val1;
info.SomeField2 = val2;
ctx.ProductInformation.InsertOnSubmit( info );
ctx.SubmitChanges();
But how to use the same column collection from above to populate the columns while iterating over that, when there is no such thing as:
info["field1"].Value = val1;
Thanks.
Just fetch the object that you want to modofy, set the property and call SubmitChanges. There is no need to create a new object and insert it. The Context tracks your changed properties and generates the update statement accordingly. In your case you may want to set the properties via reflection rather than manually since you are reading them from another table.
You'll need to use reflection. Assuming you can get the PropertyInfo from the metadata:
PropertyInfo property = GetPropertyForThisField(col.Name);
property.SetValue(info, val1, null);

Resources