I have a dictionary:
Dictionary<ICD_Map2, string> maps = new Dictionary<ICD_Map2, string>();
I add to the dictionary via button click:
private void button2_Click(object sender, EventArgs e)
{
maps.Clear();
// Load mapping file.
var reader = new StreamReader(File.OpenRead(#"Call_Details_Map.csv"));
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
maps.Add(new ICD_Map2(values[0].Replace("\"",""), values[1].Replace("\"","")), values[2].Replace("\"",""));
}
}
I want to use LINQ and map my keys to the "string" in maps.
How do I do it?
var File001 = from line in File.ReadLines(ICD_process)
let l = line.Split(',')
where l[0] != "\"Statement Date\""
select new
{
CallType = maps.ToLookup(p => l[5], p => l[3]),
Calls = l[11] == "\"\"" ? "0" : (maps.ToLookup(p => l[5], p => l[3]) == "Mobile Data" || maps.ToLookup(p => l[5], p => l[3]) == "Mobile SMS") ? "0" : l[11].Replace("\"","").ToString())
};
I am getting error in Calls variable in File001 Linq method
It's not clear what you are trying to achieve, but here is my advice. Now you are working with spitted lines array like this l[0] != "\"Statement Date\"". I think only you know what data should be at index 9. It's not very readable, error-prone (typo in Statemnet Date, wrong index), and it's very hard to maintain. Instead this create an object, which will parse line for you and provide data via strongly typed properties with nice names.
public class ICDEntry
{
public static ICDEntry CreateFrom(string line)
{
string[] values = line.Split(',');
var entry = new ICDEntry();
// assign values to properties:
// if (values[0] == "\"Statement Date\"")
// entry.StatementDate = DateTime.Parse(values[1]);
// entry.IsSomething = values[11] == "\"\""
return entry;
}
public DateTime? StatementDate { get; private set; }
public string MobileSMS { get; private set; }
public bool IsSomething { get; private set; }
}
Now you can parse each line, and then work in strongly typed world making queries to your ICD entries:
var entries = File.ReadLines(ICD_process).Select(l => ICDEntry.CreateFrom(l));
var File001 = from e in entries
where e.StatementDate.HasValue
select new {
Calls = e.IsSomething ? "0" : e.MobileSMS; // use ICDEntry here
};
Related
I cannot seem to get the desirable filtered result from my query.
Data
public class fdp_1115
{
public string Id{ get; set; }
public string Number{ get; set; }
public string Type{ get; set; }
}
List<fdp_1115> fdpList = new List<fdp_1115>
{
new fdp_1115 { Id = "1", Number = "Lot123", Type = "D14MWT" },
new fdp_1115 { Id = "2", Number = "Lot123", Type = "E12WBC7W1" }
};
List<string> searchValues = new List<string> { "MLE12WBC7W1 A R" };
LINQ:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s)));
if (LocType != null)
{
Console.WriteLine("Matching record found:");
Console.WriteLine($"Id: {LocType.Id}, Number: {LocType.Number}, Type: {LocType.Type}");
}
else
{
Console.WriteLine("No matching records found.");
}
The result I wanted is:
Matching record found:
Id: 2, Number: Lot123, Type: E12WBC7W1
But I got "No matching records found." which indicates that LocType == null.
I already tried trimming and ignoring case sensitive:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s.Trim().Replace(" ", ""))));
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s, StringComparison.InvariantCultureIgnoreCase)));
But still no luck. Any idea how do I match "MLE12WBC7W1 A R" with "E12WBC7W1"?
You have your contains the other way around.
d.Type = "E12WBC7W1"
and
s = "MLE12WBC7W1 A R"
Then "E12WBC7W1" does not Contains "MLE12WBC7W1 A R"
It is the other way around.
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => s.Contains(d.Type)));
Your current logic checks whether there is any object with Type value that contains the value for each string in the searchValues array.
From your requirement:
You want to filter the object that fulfills there is any string in searchValues containing the value of Type.
Thus it should be:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => s.Contains(d.Type)));
my question is simple but I got stuck with something. Can you tell me how can I reduce 2 select into 1 select LINQ in c#? I am using CloudNative.CloudEvents NuGet package for cloud-native events.
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
input is a parameter from cosmosDbTrigger it`s type : IReadOnlyList
OrderDocument.cs
public class OrderDocument
{
public string Id { get; private set; }
public string Json { get; private set; }
public OrderDocument(string id, string json)
{
Id = id;
Json = json;
}
public OrderEvent ToOrderEvent() => OrderEventHelper.ToOrderEvent(Json);
}
OrderEventHelper.cs
public static OrderEvent ToOrderEvent(string json)
{
ArgumentHelper.ThrowIfNullOrEmpty(json);
var orderEvent = JsonConvert.DeserializeObject<OrderEvent>(json);
var eventDefinition = OrderEvents.EventDefinitions.SingleOrDefault(_ => _.EventType == orderEvent.EventType);
return eventDefinition == null
? orderEvent
: new OrderEvent(
orderEvent.Id,
orderEvent.Source,
orderEvent.EventType,
orderEvent.Subject,
orderEvent.DataContentType,
orderEvent.DataSchema,
orderEvent.Timestamp,
JsonConvert.DeserializeObject(orderEvent.Payload.ToString(), eventDefinition.PayloadType),
orderEvent.TraceId);
}
linq extensions are basically for loops in the background. If you want to perform multiple actions against a list, perhaps making your own simple for loop where you can manage that yourself would work.
Your code:
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent())
.Select(_ =>
new CloudEvent()
{
Type = _.EventType,
Subject = _.Subject,
Source = _.Source,
Data = _
});
could be changed to:
// our result set, rather than the one returned from linq Select
var results = new List<CloudEvent>();
foreach(var x in input){
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// add the Cloud event to our result set
results.Add(new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
});
}
where you then have a result list to work with.
If you wanted to keep it all in linq, you could instead perform all of your logic in the first Select, and ensure that it returns a CloudEvent. Notice here that you can employ the use of curly brackets in the linq statement to evaluate a function rather than a single variable value:
var orderEvents = input
.Select(x =>
{
// create the order event here
var temporaryOrderEvent = new OrderDocument(x.Id, x.ToString()).ToOrderEvent();
// return the Cloud event here
return new CloudEvent()
{
Type = temporaryOrderEvent .EventType,
Subject = temporaryOrderEvent .Subject,
Source = temporaryOrderEvent .Source,
Data = temporaryOrderEvent
};
});
How about putting conversion to OrderEvent and using ToCloudEvent in the same Select?
var orderEvents = input
.Select(_ => new OrderDocument(_.Id, _.ToString()).ToOrderEvent().ToCloudEvent())
public class OrderEvent
{
public CloudEvent ToCloudEvent()
{
new CloudEvent()
{
Type = this.EventType,
Subject = this.Subject,
Source = this.Source,
Data = this
};
}
}
I would like to use this string as a filter to remove some Ids in a linq query
public class ProductKitMakerDto
{
public int Id { get; set; }
public string TitleShort { get; set; }
public string Media { get; set; }
}
[HttpPost]
public ActionResult KitItemSelect(string culture)
{
string productMakerIds = "4174,2196,2201,2460,2508,2204";
//create a list
var productMakerList = new List<ProductKitMakerDto>();
foreach (int i in productMakerIds)
{
productMakerList.Add(new ProductKitMakerDto { Id = i });
}
var itemselects = (from p in _context.Products
where p.Matrix == 2400
select new ProductKitMakerDto()
{
Id = p.Id,
TitleShort = culture == "de" ? p.TitleShortDe :
culture == "fr" ? p.TitleShortFr :
p.TitleShortEn,
Media = "/img/" + p.Photo,
}).ToList();
//From this query I get 40 results.
//Then I want to remove the ones from the list:
//itemselects = itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
//1st (above) I get an Error CS0266 asking for explicit cast. So aplly the modification
itemselects = (List<ProductKitMakerDto>)itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
return Json(itemselects, JsonRequestBehavior.AllowGet);
}
I get 500 (Internal Server Error) - xhr.send( options.hasContent && options.data || null );
I guess the list is empty.
Any idea? Thanks
this does not work
string productMakerIds = "4174,2196,2201,2460,2508,2204";
var productMakerList = new List<ProductKitMakerDto>();
foreach (int i in productMakerIds)
{
productMakerList.Add(new ProductKitMakerDto { Id = i });
}
because you need to split on comma first and parse the string to int:
foreach (string i in productMakerIds.Split(',')) // and parse i to int with int.Parse
but since it's a string literal, initialize it correctly in the first place. Don't use a List<ProductKitMakerDto> because you just need a List<int>, then you can use Contains:
var productMakerList = new List<int>
{
4174, 2196, 2201, 2460, 2508 , 2204
};
you can not cast to a list if it's not a list and Enumerable.Where does not return one:
itemselects = (List<ProductKitMakerDto>)itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
you need to append ToList after the Where
itemselects = itemselects
.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id))
.ToList();
but as mentioned, you could also use this Where before you create that list the first time, so include the condition witha Contains which should be supported:
var itemselects = (from p in _context.Products
where p.Matrix == 2400
&& !productMakerList.Contains(p.Id)
select new ProductKitMakerDto()
{
Id = p.Id,
TitleShort = culture == "de"
? p.TitleShortDe
: culture == "fr" ? p.TitleShortFr : p.TitleShortEn,
Media = "/img/" + p.Photo,
}).ToList();
foreach (string i in productMakerIds.Split(','))
{
productMakerList.Add(new ProductKitMakerDto { Id = int.Parse(i) });
}
i need some help with my sort script. I wanna sort some files.
This is how the Name is constructed: Name#Page#Version
I can pick the Name/category and the page but i dont know how to pick the last version :/
Here you can see an example.
foreach(string files in Directory.GetFiles(path).OrderBy(fi => fi.Length))
{
try
{
filename = Path.GetFileNameWithoutExtension(files);
index = filename.LastIndexOf("#");
index2 = filename.LastIndexOf("#",index-1);
strversion = filename.Substring(index+1);
strpage = filename.Substring(index2+1);
strpage = strpage.Substring(0, strpage.LastIndexOf("#"));
page = Int32.Parse(strpage);
version = Int32.Parse(strversion);
Console.WriteLine("Page: "+page);
Console.WriteLine("Version: "+version);
if (filename.Contains("SMA"))
{
if (page == 1)
{
Console.WriteLine(filename);
}
}
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine(e.Message);
}
}
You're over complicating things, you can split the string by # and get what you want from the array given:
var fileName = "SMA#1#2";
var parts = fileName.Split('#');
var name = parts[0];
var page = parts[1];
var version = parts[2];
EDIT
As for getting the last version for each page, you're probably better off creating some sort of class for your file and then grouping by page, and then sorting by version, and then selecting the first one:
public class Program
{
public static void Main()
{
var fileNames = new[] { "SMA#1#1", "SMA#1#2", "SMA#1#3", "SMA#2#1", "SMA#2#3" };
var files = (from fileName in fileNames select fileName.Split('#') into parts let name = parts[0] let page = Int32.Parse(parts[1]) let version = Int32.Parse(parts[2]) select new MyFile(name, page, version)).ToList();
var grouped = files.GroupBy(x => x.Page).ToList();
foreach (var group in grouped)
{
var ordered = group.OrderByDescending(x => x.Version);
Console.WriteLine($"Page {group.Key} highest version: {ordered.First().Version}");
}
}
}
public class MyFile
{
public string Name { get; set; }
public int Page { get; set; }
public int Version { get; set; }
public MyFile(string name, int page, int version)
{
Name = name;
Page = page;
Version = version;
}
}
If I correctly understand your requirement, you want to
filter out every file not containing "SMA"
then order by page
then by version
You can achieve this quite declaratively using LINQ:
var orderedFileNames =
fileNames
.Where(fn=>fn.Contains("SMA")
// parse name
.Select(fn => fn.Split('#'))
// pull parts into anonymous type
.Select(fn => new {
Name = fn[0], Page = int.Parse(fn[1]), Version = int.Parse(fn[2])
})
.OrderBy(fn=>fn.Name)
.ThenBy(fn=>fn.Page)
.ThenBy(fn=>fn.Version);
int lastIndex = filename.LastIndexOf("#");
string version = fileName.SubString(lastIndex, fileName.Length - lastIndex);
Is that what you are looking for?
I read text file and displayed in DataGridView data is displaying, but in the above text file is related to log files, I want to display that log file by month wise, without using a DataTable, if possible.
private void BtnUser_Click(object sender, EventArgs e)
{
dgv1.Columns.Add("col1", "Ipaddress");
dgv1.Columns.Add("col2", "Sysname");
dgv1.Columns.Add("col3", "username");
dgv1.Columns.Add("col4", "text");
dgv1.Columns.Add("col5", "datetime");
string line;
StreamReader strRead = new StreamReader("D:\\login.lgl");
{
int row = 0;
while ((line = strRead.ReadLine()) != null)
{
string[] columns = line.Split('|');
dgv1.Rows.Add();
for (int i = 0; i < columns.Length; i++)
{
dgv1[i, row].Value = columns[i];
}
row++;
}
}
}
You could use Linq to group by month:
var logMonthGroups = File.ReadLines("D:\\login.lgl")
.Select(l => new { Cols = l.Split('|') })
.Select(x => new
{
Ipaddress = x.Cols.ElementAtOrDefault(0),
Sysname = x.Cols.ElementAtOrDefault(1),
username = x.Cols.ElementAtOrDefault(2),
text = x.Cols.ElementAtOrDefault(3),
datetime = x.Cols.ElementAtOrDefault(4) == null ? DateTime.MinValue : DateTime.Parse(x.Cols[4])
})
.GroupBy(x => new { Year = x.datetime.Year, Month = x.datetime.Month })
.OrderBy(g => g.Key.Year).ThenBy(g => g.Key.Month);
foreach(var group in logMonthGroups)
{
// add to the DataGridView ...
}
I would recommend that you create a class for the structure you are parsing in from the file, something like:
public class LogFileItem
{
public string IpAddress {get; set;}
public string Sysname {get; set;}
public string Username {get; set;}
public string Text {get; set;}
public DateTime DateTime {get; set;}
public static List<LogFileItem> ParseLogFile(string path)
{
List<LogFileItem> result = new List<LogFileItem>();
//in a real scenario, this code should have a lot more error checks
string line;
StreamReader strRead = new StreamReader(path);
while ((line = strRead.ReadLine()) != null)
{
string[] columns = line.Split('|');
LogFileItem item = new LogFileItem();
item.IpAddress = columns[0];
item.Sysname = columns[1];
item.Username = columns[2];
item.Text = columns[3];
//this assumes that the dateTime column is parsable by .net
item.DateTime = DateTime.Parse(columns[4]);
result.add(item);
}
return result;
}
}
then you could just do:
private void BtnUser_Click(object sender, EventArgs e)
{
List<LogFileItem> logItems = LogFileItem.ParseLogFile(#"D:\login.lgl");
dgv1.DataSource = logItems;
}
to display the data. Also you could filter the data any which way you want, and if you have a month/year pair to filter on, you could just do:
List<LogFileItem> logItems = LogFileItem.ParseLogFile(#"D:\login.lgl");
var logsPerMonth = logItems.Where(li => li.DateTime.Year = year && li.DateTime.Month == month);
Note that datetime parsing is somewhat of a dark art, so you could take a look at DateTime.ParseExact to make that work. Also, take a look at using an using statement, or reading the lines from a text file with File.ReadAllLines.