Querying Distinct Events from Google Calendar - c#

Right now I have a very simple query that pulls up entries that have a string and a specific date range.
EventQuery eQuery = new EventQuery(calendarInfo.Uri.ToString());
eQuery.Query = "Tennis";
eQuery.StartDate = startDate;
eQuery.EndDate = endDate;
EventFeed myResultsFeed = _service.Query(eQuery);
After querying, myResultsFeed will contain an atomEntryCollection. Each atomEntry has a Title. The way I have it set up, there could be multiple entries with the same title.
I would like my Query to be able to select UNIQUE titles. Is this possible?
Link to the API Docs
I hypothesized that I could use a WHERE object
Where x = new Where();
x.yadayada();
but it can't be passed to _service.Query()
I'm also exploring the .extraparameters object. is it possible to do something like this?
eQuery.ExtraParameters = "distinct";
Looking into the "Partial Response" feature..
http://code.google.com/apis/gdata/docs/2.0/reference.html#PartialResponse
it looks pretty promising..

I don't think what you're trying to do is possible using the Google Data API.
However, extenting upon #Fueled answer, you could do something like this if you need a collection of AtomEntry's.
// Custom comparer for the AtomEntry class
class AtomEntryComparer : IEqualityComparer<AtomEntry>
{
// EventEntry are equal if their titles are equal.
public bool Equals(AtomEntry x, AtomEntry y)
{
// adjust as needed
return x.Title.Text.Equals(y.Title.Text);
}
public int GetHashCode(AtomEntry entry)
{
// adjust as needed
return entry.Title.Text.GetHashCode();
}
}
EventFeed eventFeed = service.Query(query)
var entries = eventFeed.Entries.Distinct(new AtomEntryComparer());

It's probably not the solution you were looking for, but since you have in hand an AtomEntryCollection (which down the line implements IEnumerable<T>), you could use LINQ to retrieve the distinct titles, like so:
EventFeed feed = service.Query(query);
var uniqueEntries =
(from e in feed.Entries
select e.Title.Text).Distinct();
And then loop over them with a simple foreach:
foreach (var item in uniqueEntries)
{
Console.WriteLine(item);
}
But then you have only a collection of string representing the Event titles, and not a collection of AtomEntry. I guess you could link them together in a Dictionary.
Not optimal, but should work.

Related

Why is RemoveAll(x => x.Condition) removing all my records?

I'm working on creating a filter for a collection of employees. In order to do this I initially fetch a raw collection of all employees. I clone this list so I can iterate over the original list but remove items from the second list.
For each filter I have, I build a collection of employee ids that pass the filter. Having gone through all filters I then attempt to remove everything that isn't contained in any of these lists from the cloned list.
However for some reason, whenever I attempt to do this using .RemoveAll(), all records seemed to be removed and I can't figure out why.
Here is a stripped down version of the method I'm using, with only 1 filter applied:
public List<int> GetFilteredEmployeeIds(int? brandId)
{
List<int> employeeIds = GetFilteredEmployeeIdsBySearchTerm();
List<int> filteredEmployeeIds = employeeIds.Clone();
// Now filter the results based on which checkboxes are ticked
foreach (var employeeId in employeeIds)
{
// 3rd party API used to get values - please ignore for this example
Member m = new Member(employeeId);
if (m.IsInGroup("Employees"))
{
int memberBrandId = Convert.ToInt32(m.getProperty("brandID").Value);
// Filter by brand
List<int> filteredEmployeeIdsByBrand = new List<int>();
if (brandId != null)
{
if (brandId == memberBrandId)
filteredEmployeeIdsByBrand.Add(m.Id);
var setToRemove = new HashSet<int>(filteredEmployeeIdsByBrand);
filteredEmployeeIds.RemoveAll(x => !setToRemove.Contains(x));
}
}
}
return filteredEmployeeIds;
}
As you can see, I'm basically attempting to remove all records from the cloned record set, wherever the id doesn't match in the second collection. However for some reason every record seems to be getting removed.
Anybody know why?
P.S: Just to clarify, I have put in logging to check the values throughout the process and there are records appearing in the second list, however for whatever reason they're not getting matched in the RemoveAll()
Thanks
Ok only minutes after posting this I realised what I did wrong: The scoping is incorrect. What it should've been was like so:
public List<int> GetFilteredEmployeeIds(int? brandId)
{
List<int> employeeIds = GetFilteredEmployeeIdsBySearchTerm();
List<int> filteredEmployeeIds = employeeIds.Clone();
List<int> filteredEmployeeIdsByBrand = new List<int>();
// Now filter the results based on which checkboxes are ticked
foreach (var employeeId in employeeIds)
{
Member m = new Member(employeeId);
if (m.IsInGroup("Employees"))
{
int memberBrandId = Convert.ToInt32(m.getProperty("brandID").Value);
// Filter by brand
if (brandId != null)
{
if (brandId == memberBrandId)
filteredEmployeeIdsByBrand.Add(m.Id);
}
}
}
var setToRemove = new HashSet<int>(filteredEmployeeIdsByBrand);
filteredEmployeeIds.RemoveAll(x => !setToRemove.Contains(x));
return filteredEmployeeIds;
}
Essentially the removal of entries needed to be done outside the loop of the employee ids :-)
I know that you said your example was stripped down, so maybe this wouldn't suit, but could you do something like the following:
public List<int> GetFilteredEmployeeIds(int? brandId)
{
List<int> employeeIds = GetFilteredEmployeeIdsBySearchTerm();
return employeeIds.Where(e => MemberIsEmployeeWithBrand(e, brandId)).ToList();
}
private bool MemberIsEmployeeWithBrand(int employeeId, int? brandId)
{
Member m = new Member(employeeId);
if (!m.IsInGroup("Employees"))
{
return false;
}
int memberBrandId = Convert.ToInt32(m.getProperty("brandID").Value);
return brandId == memberBrandId;
}
I've just done that off the top of my head, not tested, but if all you need to do is filter the employee ids, then maybe you don't need to clone the original list, just use the Where function to do the filtering on it directly??
Please someone let me know if i've done something blindingly stupid!!

check if collection of objects where each contain another collection of objects contain all values of List<string> via LINQ

I have a collection of objects where each object contains another collection of objects. I need to find out the fastest way to check if it contains all values of List<string>.
Here is an example:
class Video {
List<Tag> Tags;
}
class Tag{
public Tag (string name){
Name = name;
}
string Name;
}
List<string> selectedTags = new List<string>();
selectedTags.Add("Foo");
selectedTags.Add("Moo");
selectedTags.Add("Boo");
List<Video> videos = new List<Video>();
// Case A
Video videoA = new Video();
videoA.Tags = new List<Tag>();
videoA.Tags.Add(new Tag("Foo"));
videoA.Tags.Add(new Tag("Moo"));
videos.Add(videoA);
videoA should not be selected by LINQ because it doesn't contain all tags.
// Case B
Video videoB = new Video();
videoB.Tags = new List<Tag>();
videoB.Tags.Add(new Tag("Foo"));
videoB.Tags.Add(new Tag("Moo"));
videoB.Tags.Add(new Tag("Boo"));
videos.Add(videoB);
videoB should be selected by LINQ because it contains all tags.
I tried this with foreach loops, but it's too slow so I'm looking for a LINQ solution.
foreach (Video video in videos) {
if (video.Tags.Count() > 0) {
bool containAllTags = true;
foreach (string tagToFind in selectedTags) {
bool tagFound = false;
foreach (Tag tagItem in video.Tags) {
if (tagToFind == tagItem.Name)
tagFound = true;
}
if (!tagFound)
containAllTags = false;
}
if (containAllTags)
result.Add(videoItem);
}
}
The resulting LINQ should look like this:
IEnumerable<Video> = from vid in videos
where vid.Tags.( ..I dont know.. )
select vid;
I tried several ways with .Any, .All, etc.. but I can't find the solution and I can't use .Intersect because one is a List of strings and the other is a List of objects. Note that in the production version, Video and Tag elements have many more properties.
With your current code, you logically want:
IEnumerable<Video> result = from vid in videos
where selectedTags.All(tag =>
vid.Tags.Any(t => t.Name == tag))
select vid;
Or equivalently:
var result = videos.Where(vid => selectedTags.All(tag =>
vid.Tags.Any(t => t.Name == tag)));
This is assuming you've made Tag.Name and Video.Tags public, of course - ideally as properties rather than as fields.
Note how we're calling All against selectedTags, as (assuming I've read your requirements correctly) it's important that all the selected tags are present in the video - it's not important that all the video's tags are selected.
Now that could be relatively slow, if you have a lot of tags to check and a lot of tags per video.
However, knowing how to optimize it will really depend on some other choices:
If the order of the tags isn't important, could you change Video.Tags to be a set instead of a list?
Are you always looking through the same set of videos, so you could perform some pre-processing?
Is the total number of tags available large? What about the number of tags per video? What about the number of selected tags?
Alternatively, you can project each video to its "list of tags" and check whether there are any in the selected set which aren't in the video's set:
var result = videos.Where(vid => !selectedTags.Except(vid.Tags.Select(t => t.Name))
.Any());

C# - sorting by a property

I am trying to sort a collection of objects in C# by a custom property.
(For context, I am working with the Twitter API using the Twitterizer library, sorting Direct Messages into conversation view)
Say a custom class has a property named label, where label is a string that is assigned when the class constructor.
I have a Collection (or a List, it doesn't matter) of said classes, and I want to sort them all into separate Lists (or Collections) based on the value of label, and group them together.
At the moment I've been doing this by using a foreach loop and checking the values that way - a horrible waste of CPU time and awful programming, I know. I'm ashamed of it.
Basically I know that all of the data I have is there given to me, and I also know that it should be really easy to sort. It's easy enough for a human to do it with bits of paper, but I just don't know how to do it in C#.
Does anyone have the solution to this? If you need more information and/or context just ask.
Have you tried Linq's OrderBy?
var mySortedList = myCollection.OrderBy(x => x.PropertyName).ToList();
This is still going to loop through the values to sort - there's no way around that. This will at least clean up your code.
You say sorting but it sounds like you're trying to divide up a list of things based on a common value. For that you want GroupBy.
You'll also want ToDictionary to switch from an IGrouping as you'll presumably be wanting key based lookup.
I assume that the elements within each of the output sets will need to be sorted, so check out OrderBy. Since you'll undoubtedly be accessing each list multiple times you'll want to collapse it to a list or an array (you mentioned list) so I used ToList
//Make some test data
var labels = new[] {"A", "B", "C", "D"};
var rawMessages = new List<Message>();
for (var i = 0; i < 15; ++i)
{
rawMessages.Add(new Message
{
Label = labels[i % labels.Length],
Text = "Hi" + i,
Timestamp = DateTime.Now.AddMinutes(i * Math.Pow(-1, i))
});
}
//Group the data up by label
var groupedMessages = rawMessages.GroupBy(message => message.Label);
//Convert to a dictionary for by-label lookup (this gives us a Dictionary<string, List<Message>>)
var messageLookup = groupedMessages.ToDictionary(
//Make the dictionary key the label of the conversation (set of messages)
grouping => grouping.Key,
//Sort the messages in each conversation by their timestamps and convert to a list
messages => messages.OrderBy(message => message.Timestamp).ToList());
//Use the data...
var messagesInConversationA = messageLookup["A"];
var messagesInConversationB = messageLookup["B"];
var messagesInConversationC = messageLookup["C"];
var messagesInConversationD = messageLookup["D"];
It sounds to me like mlorbetske was correct in his interpretation of your question. It sounds like you want to do grouping rather than sorting. I just went at the answer a bit differently
var originalList = new[] { new { Name = "Andy", Label = "Junk" }, new { Name = "Frank", Label = "Junk" }, new { Name = "Lisa", Label = "Trash" } }.ToList();
var myLists = new Dictionary<string, List<Object>>();
originalList.ForEach(x =>
{
if (!myLists.ContainsKey(x.Label))
myLists.Add(x.Label,new List<object>());
myLists[x.Label].Add(x);
});

How to filter on multiple SubItems in ObjectListView

So, I am trying to programmatically add in a ModelFilter to my ObjectListView that will look at two (or more) columns and filters on each separately. Currently, I think that ObjectListView only supports one filter, but I may be missing something in the code/documentation.
As an example, one of my intended filters is to look at column "Active" and that has values of "A" or "T". Another column is a Supervisor Name. So, I want to find all entries where Supervisor name = "Smith" and Active = "A".
I can get the filter to work for either of these options separately using TextMatchFilter, but cannot figure out how to get both to work at the same time.
The minor problem I see is that if the Supervisor Name contains an "A", then using the standard Filter will return the whole row. I have been able to get around that by programmatically setting the Searchable property for columns to false if I don't want to look at them, and then turn them back on once the list is filtered. However, I have a feeling that if I turn Searchable on for the Supervisor column, I will get the unwanted results.
Does anyone know of a way to get the filter to work on multiple columns, using only the indicated columns for each filter?
(I have no sample code to show that helps in solving this. However, if you really want to see what I have for my filtering code, I will be happy to add that; it is in VB however).
Current Code - This looks at a value chosen by the user (searchMeth) and enables searching on that column. It then does the search for what was entered in the txtSearch box. However, in addition to this, I want to add in an additional filter for Supervisor. (See the AndAlso comment
olvEmps.UseFiltering = True
OlvColumn1.Searchable = False
OlvColumn2.Searchable = False
OlvColumn4.Searchable = False
OlvColumn3.Searchable = False
OlvColumn5.Searchable = False
Select Case searchMeth
Case "Name"
OlvColumn1.Searchable = True
Case "Employee Number"
OlvColumn2.Searchable = True
Case "Department"
OlvColumn3.Searchable = True
End Select
olvEmps.OwnerDraw = True
Dim tFilter As BrightIdeasSoftware.TextMatchFilter = BrightIdeasSoftware.TextMatchFilter.Contains(olvEmps, txtSearch.Text)
'andalso olvColumn5 = supeName?
olvEmps.ModelFilter = tFilter
olvEmps.DefaultRenderer = New BrightIdeasSoftware.HighlightTextRenderer(tFilter)
OlvColumn1.Searchable = True
OlvColumn2.Searchable = True
OlvColumn3.Searchable = True
OlvColumn4.Searchable = True
OlvColumn5.Searchable = True
I'm sure the PredicateBuilder solution will work, but ObjectListView comes with a simpler solution already.
TextMatchFilter can be limited to which columns it searches via the Columns property. Set this to an array of columns that you want to consider.
TextMatchFilter filter1 = TextMatchFilter.Contains(olvEmps, txtSearch.Text)
filter1.Columns = new [] { this.olvColumn1, this.olvColumn2 };
You can combine two filters using the CompositeAllFilter to match two or more other filters.
this.olvEmps.ModelFilter = new CompositeAllFilter(new List<IModelFilter> { filter1, filter2 });
Though I don't yet fully understand your deal, I'll give it a shot with the PredicateBuilder that is part of the LINQKit assembly which you can download here.
As such, filtering on multiple columns shall get easy. Perhaps shall you consider to reset the binding of your ObjectListView control once your source collection has been filtered.
Grossly, I would do about the following:
Load your datum;
Display them through data binding;
Once a column is clicked for filter, make a call to your "Filter" method which will apply your predicates;
Rebind your control with the new filtered collection.
Please refer to the PredicateBuilder documentation at the link provided previously. Another example to building dynamic filters is illustrated here: "How would this query translate into a dynamic Linq expression?" for a search engine I implemented.
In my case, the filters were applied directly against the database results. Aside, it can even be used in your situation with in-memory datum since it is Linq based.
I'm sure I'll be able to provide further assitance when you post your code sample for filtering the information.
EDIT #1
After I have read the code sample provided, here's what I believe would do the trick. As for the Searchable property, I am no familiar of this approach, so maybe I can miss something important out of your code and if it is so, feel free to point me what I could have missed. =)
Note that I assume that all of your datum are string, since I am verifying whether your datum is null or white space. Furthermore, the way I see it, to filter a result set is to bring visible only records which meet certain criterion. You don't want to see what doesn't meet the criterion. It's the same as a WHERE clause in SQL.
public class FilterCriterion {
public bool HasEmployeeName { get { return !string.IsNullOrWhiteSpace(EmployeeName); } }
public bool HasEmployeeNumber { get { return !string.IsNullOrWhiteSpace(EmployeeNumber); } }
public bool HasDepartment { get { return !string.IsNullOrWhiteSpace(Department); } }
public string EmployeeName { get; set; }
public string EmployeeNumber { get; set; }
public string Department { get; set; }
}
The FilterCriterion class shall be used to apply any filter that you want against your data source, collection or whatsoever.
var employees = LoadEmployeesFromUnderlyingDataStore();
var criterion = new FilterCriterion();
switch(searchMeth) {
case "Name": filter.EmployeeName = "the name to filter by"; break;
case "EmployeeNumber": filter.EmployeeNumber = "the number to filter by"; break;
case "Department": filter.Department = "the department to filter by"; break;
}
var filter = PredicateBuilder.True<Employee>(); // assuming you have an employee class.
if (criterion.HasEmployeeName)
filter.And(e => e.Name.ContainsLike(criterion.EmployeeName));
if (criterion.HasEmployeeNumber)
filter.And(e => e.EmployeeNumber.ContainsLike(criterion.EmployeeNumber));
if (criterion.HasDepartment)
filter.And(e => e.Department.ContainsLike(criterion.Department));
var filteredEmployees = employees.Where(filter);
// Supply your ObjectListView the way you're used to and this shall function.
Aside, you could also, if you have to deal with such string variables write a ContainsLike extension method to the string class.
namespace System {
public static class StringExtensions {
public static bool ContainsLike(this string input, string value) {
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
input = input.ToLower().RemoveDiacritics();
value = value.ToLower().RemoveDiacritics();
if (string.IsNullOrWhiteSpace(input) || string.IsNullOrWhiteSpace(value)) return false;
return input.Contains(value);
}
public static string RemoveDiacritics(this string input) {
return input == null ? null :
Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(input));
}
}
}
I do hope this helps, otherwise inform me of what I misunderstood from your question and we'll try to figure this out together.
Should you need the VB version of this code, I'll try to translate to the best of my VB knowledge.
This code is provided as is and has not been tested, except for both the string extension methods.

Is there a way to access the columns in a Dapper FastExpando via string or index?

I am pulling in a Dapper FastExpando object and want to be able to reference the column names dynamically at run time rather than at design/compile time. So I want to be able to do the following:
var testdata = conn.Query("select * from Ride Where RiderNum = 21457");
I want to be able to do the following:
foreach( var row in testdata) {
var Value = row["PropertyA"];
}
I understand that I can do:
var Value = row.PropertyA;
but I can't do that since the name of the property i'm going to need won't be known until runtime.
The answer from this SO Question doesn't work. I still get the same Target Invocation exception. So...
Is there any way to do what I want to do with a Dapper FastExpando?
Sure, it is actually way easier than that:
var sql = "select 1 A, 'two' B";
var row = (IDictionary<string, object>)connection.Query(sql).First();
row["A"].IsEqualTo(1);
row["B"].IsEqualTo("two");
Regarding the portion of the title "or index?" - I needed to access results by index since the column names being returned changed sometimes, so you can use a variation of Sam Saffron's answer like this:
var sql = "select 1, 'two'";
var row = (IDictionary<string, object>)connection.Query(sql).First();
row.Values.ElementAt(0).IsEqualTo(1);
row.Values.ElementAt(1).IsEqualTo("two");
There a simple way to access fields direct below sample
string strConexao = WebConfigurationManager.ConnectionStrings["connection"].ConnectionString;
conexaoBD = new SqlConnection(strConexao);
conexaoBD.Open();
var result = conexaoBD.Query("Select Field1,Field2 from Table").First();
//access field value result.Field1
//access field value result.Field2
if (result.Field1 == "abc"){ dosomething}

Categories

Resources