I have the following string list of different sizes
[5].[1].[2].[3].[4].__class SetObjectModel
[5].[1].[4].__class SetObjectModel
[5].[1].[4].[3].[1].__class SetObjectModel
I need to remove all other brackets and just leave the first one:
[5].__class SetObjectModel
Does anyone have any suggestions on how I might achieve this?
Here a full sample of using the Split feature of a string and the Join.
You can read more about Split here and Join here
// source list of string to modify
var source = new List<string>()
{
"[5].[1].[2].[3].[4].__class SetObjectModel",
"[5].[1].[4].__class SetObjectModel",
"[5].[1].[4].[3].[1].__class SetObjectModel"
};
// convert each element of source into a result set
var results = source.Select(value =>
{
// split by the period
var splitted = value.Split(new[] { "." }, StringSplitOptions.None);
// join the first and last element with a period to match the format you want
return string.Join(".", new[] { splitted.First(), splitted.Last() });
}).ToList();
Here's the second portion of converting without using Linq and other quick 1 liner in case you are not familiar with them
List<string> result = new List<string>();
foreach (string value in source)
{
// split by the period
string[] splitted = value.Split(new[] { "." }, StringSplitOptions.None);
// will contain the elements to keep and join
List<string> elements = new List<string>();
// add first element of the split
elements.Add(splitted[0]);
// add the last element of the split
elements.Add(splitted[splitted.Length - 1]);
// join the elements together
string join = string.Join(".", elements);
// add the join to the result set
result.Add(join);
}
Related
I have a List contain some strings inside like this and other data.
HwndWrapper[App.exe;;cda6c3f4-8c87-4b12-8f3d-5322ca90eeex]
HwndWrapper[App.exe;;cadac3f4-8c87-4b12-8q3d-1qwe2ca90eec]
HwndWrapper[App.exe;;c1b6a3s4-8c87-4b12-8f3d-2qw2ca90eeev]
My list:
// Returns a list of WindowInformation objects with Handle, Caption, Class,
// Parent, Children, Siblings and process information
List<WindowInformation> windowListExtended = WindowList.GetAllWindowsExtendedInfo();
The regular expresion to match is:
HwndWrapper\[App.exe;;.*?\]
Now for every match on the list. I need extract the string matched and run a process with every string extracted, Foreach or something like that.
Some help please.
Update:
Thanks Altaris for the help, just need convert List to string
var message = string.Join(",", windowListExtended);
string pattern = #"HwndWrapper\[LogiOverlay.exe;;.*?]";
MatchCollection matches = Regex.Matches(message, pattern);
From what I understand you want to extract every match in a separate list to work with, there you go:
var someList = new List<string>{"HwndWrapper[App.exe;;cda6c3f4-8c87-4b12-8f3d-5322ca90eeex]",
"HwndWrapper[App.exe;;cadac3f4-8c87-4b12-8q3d-1qwe2ca90eec]",
"HwndWrapper[App.exe;;c1b6a3s4-8c87-4b12-8f3d-2qw2ca90eeev]"};
Regex FindHwndWrapper = new Regex(#"HwndWrapper\[App.exe;;(.*)\]");
var matches = someList.Where(s => FindHwndWrapper.IsMatch(s)).ToList();
foreach(var match in matches)
{
Console.WriteLine(match);// Use values
}
I used System.Linq function Where() to iterate through list
Use this Linq line if you want just the id parts, like "cda6c3f4-8c87-4b12-8f3d-5322ca90eeex"
var matches = someList.Select(s => FindHwndWrapper.Match(s).Groups[1]).ToList();
I am unsure of what you want exactly, I think you want to extract these
List<string> windowListExtended = new List<string>();
windowListExtended.Add("HwndWrapper[App.exe;;cda6c3f4-8c87-4b12-8f3d-5322ca90eeex]");
windowListExtended.Add("HwndWrapper[App.exe;;cadac3f4-8c87-4b12-8q3d-1qwe2ca90eec]");
windowListExtended.Add("HwndWrapper[App.exe;;c1b6a3s4-8c87-4b12-8f3d-2qw2ca90eeev]");
var myRegex = new Regex(#"HwndWrapper\[App.exe;;.*?]");
var resultList = files.Where(x => myRegex.IsMatch(x)).Select(x => x.Split(new[] { ";;","]" }, StringSplitOptions.None)[1]).ToList();
//Now resultList contains => cda6c3f4-8c87-4b12-8f3d-5322ca90eeex, cadac3f4-8c87-4b12-8q3d-1qwe2ca90eec, c1b6a3s4-8c87-4b12-8f3d-2qw2ca90eeev
foreach (var item in resultList)
{
//Do whatever you want
}
I've got dates from separate countries within a single List<>. I'm trying to get two records that contain the same characters before the second comma, and replace BOTH of those items with a new one.
Example:
From This:
18/04/2014,Good Friday,England and Wales
18/04/2014,Good Friday,Scotland
Into this:
18/04/2014,Good Friday,"England, Wales and Scotland"
Please note there may be multiple scenarios within the list like the above example. I've managed to get everything before the second Comma with:
splitSubstring = line.Remove(line.LastIndexOf(','));
I've tried the below, but it's clearly flawed since it won't delete both the records even if it does find a match:
foreach (var line in orderedLines)
{
if (splitSubstring == line.Remove(line.LastIndexOf(',')))
{
//Replace if previous is match here
}
splitSubstring = line.Remove(line.LastIndexOf(','));
File.AppendAllText(correctFile, line);
}
I would suggest parsing it into a structure you can work with e.g.
public class HolidayInfo
{
public DateTime Date { get; set; }
public string Name { get; set; }
public string[] Countries { get; set; }
};
And then
string[] lines = new string[]
{
"18/04/2014,Good Friday,England and Wales",
"18/04/2014,Good Friday,Scotland"
};
// splits the lines into an array of strings
IEnumerable<string[]> parsed = lines.Select(l => l.Split(','));
// copy the parsed lines into a data structure you can write code against
IEnumerable<HolidayInfo> info = parsed
.Select(l => new HolidayInfo
{
Date = DateTime.Parse(l[0]),
Name = l[1],
Countries = l[2].Split(new[] {",", " and " }, StringSplitOptions.RemoveEmptyEntries)
});
...etc. And once you have it in a helpful data structure you can begin to develop the required logic. The above code is just an example, the approach is what you should focus on.
I ended up using LINQ to pull apart the List and .Add() them into another based on an if statement. LINQ made it nice and simple.
//Using LINQ to seperate the two locations from the list.
var seperateScotland = from s in toBeInsertedList
where s.HolidayLocation == scotlandName
select s;
var seperateEngland = from e in toBeInsertedList
where e.HolidayLocation == engAndWales
select e;
Thanks for pointing me to LINQ
I have a file with "Name|Number" in each line and I wish to remove the lines with names that contain another name in the list.
For example, if there is "PEDRO|3" , "PEDROFILHO|5" , "PEDROPHELIS|1" in the file, i wish to remove the lines "PEDROFILHO|5" , "PEDROPHELIS|1".
The list has 1.8 million lines, I made it like this but its too slow :
List<string> names = File.ReadAllLines("firstNames.txt").ToList();
List<string> result = File.ReadAllLines("firstNames.txt").ToList();
foreach (string name in names)
{
string tempName = name.Split('|')[0];
List<string> temp = names.Where(t => t.Contains(tempName)).ToList();
foreach (string str in temp)
{
if (str.Equals(name))
{
continue;
}
result.Remove(str);
}
}
File.WriteAllLines("result.txt",result);
Does anyone know a faster way? Or how to improve the speed?
Since you are looking for matches everywhere in the word, you will end up with O(n2) algorithm. You can improve implementation a bit to avoid string deletion inside a list, which is an O(n) operation in itself:
var toDelete = new HashSet<string>();
var names = File.ReadAllLines("firstNames.txt");
foreach (string name in names) {
var tempName = name.Split('|')[0];
toDelete.UnionWith(
// Length constraint removes self-matches
names.Where(t => t.Length > name.Length && t.Contains(tempName))
);
}
File.WriteAllLines("result.txt", names.Where(name => !toDelete.Contains(name)));
This works but I don't know if it's quicker. I haven't tested on millions of lines. Remove the tolower if the names are in the same case.
List<string> names = File.ReadAllLines(#"C:\Users\Rob\Desktop\File.txt").ToList();
var result = names.Where(w => !names.Any(a=> w.Split('|')[0].Length> a.Split('|')[0].Length && w.Split('|')[0].ToLower().Contains(a.Split('|')[0].ToLower())));
File.WriteAllLines(#"C:\Users\Rob\Desktop\result.txt", result);
test file had
Rob|1
Robbie|2
Bert|3
Robert|4
Jan|5
John|6
Janice|7
Carol|8
Carolyne|9
Geoff|10
Geoffrey|11
Result had
Rob|1
Bert|3
Jan|5
John|6
Carol|8
Geoff|10
I have a dictionary with a list of strings that each look something like:
"beginning|middle|middle2|end"
Now what I wanted was to do this:
List<string> stringsWithPipes = new List<string>();
stringWithPipes.Add("beginning|middle|middle2|end");
...
if(stringWithPipes.Contains("beginning|middle|middle2|end")
{
return true;
}
problem is, the string i'm comparing it against is built slightly different so it ends up being more like:
if(stringWithPipes.Contains(beginning|middle2|middle||end)
{
return true;
}
and obviously this ends up being false. However, I want to consider it true, since its only the order that is different.
What can I do?
You can split your string on | and then split the string to be compared, and then use Enumerable.Except along with Enumerable.Any like
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
stringsWithPipes.Add("beginning|middle|middle3|end");
stringsWithPipes.Add("beginning|middle2|middle|end");
var array = stringsWithPipes.Select(r => r.Split('|')).ToArray();
string str = "beginning|middle2|middle|end";
var compareArray = str.Split('|');
foreach (var subArray in array)
{
if (!subArray.Except(compareArray).Any())
{
//Exists
Console.WriteLine("Item exists");
break;
}
}
This can surely be optimized, but the above is one way to do it.
Try this instead::
if(stringWithPipes.Any(P => P.split('|')
.All(K => "beginning|middle2|middle|end".split('|')
.contains(K)))
Hope this will help !!
You need to split on a delimeter:
var searchString = "beginning|middle|middle2|end";
var searchList = searchString.Split('|');
var stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
...
return stringsWithPipes.Select(x => x.Split('|')).Any(x => Match(searchList,x));
Then you can implement match in multiple ways
First up must contain all the search phrases but could include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x));
}
Or must be all the search phrases cannot include others.
bool Match(string[] search, string[] match) {
return search.All(x => match.Contains(x)) && search.Length == match.Length;
}
That should work.
List<string> stringsWithPipes = new List<string>();
stringsWithPipes.Add("beginning|middle|middle2|end");
string[] stringToVerifyWith = "beginning|middle2|middle||end".Split(new[] { '|' },
StringSplitOptions.RemoveEmptyEntries);
if (stringsWithPipes.Any(s => !s.Split('|').Except(stringToVerifyWith).Any()))
{
return true;
}
The Split will remove any empty entries created by the doubles |. You then check what's left if you remove every common element with the Except method. If there's nothing left (the ! [...] .Any(), .Count() == 0 would be valid too), they both contain the same elements.
I need to read a text file like this
MyItemName = Description # MoreInfo
Now I need to convert this 3 fields in to a table. using the '=' and '#' as pattern.
Just splitting on = and # - this returns and IEnumerable of an anonymous class with the properties you are interested in:
var items = File.ReadAllLines(fileName)
.Skip(1) //Skip header
.Where( line => !string.IsNullOrWhiteSpace(line))
.Select(line =>
{
var columns = line.Split('=', '#');
return new
{
ItemName = columns[0].Trim(),
Description = columns[1].Trim(),
MoreInfo = columns[2].Trim()
};
});
This approach would require the separator tokens to be used as separators exclusively - if they do occur in any of the fields, this will mess up everything and void this approach.
if you really want to use linq for it...
It doesn't look very nice and it doesn't create a table, but you get the point:
from line in File.ReadAllLines(filename)
let eqPos = line.IndexOf('=')
let atPos = line.IndexOf('#')
select new {
Name = line.Substring(0, eqPos).Trim(),
Desc = line.Substring(eqPos + 1, atPos - (eqPos + 1)).Trim(),
Info = line.Substring(atPos + 1).Trim()
}