C# Splitting a list based on items - c#

I have a list with following items (lets call it 'main list'):
[1,2,2,3,1,2,3,4,4,1,2,2]
My goal is to split it into smaller lists that will contain '1' and the following numbers (until the next '1' occurs).
The end result should look like this:
[1,2,2,3]
[1,2,3,4,4]
[1,2,2]
Some additional info:
small lists can be of different lengths
the main list always starts with '1' (so you don't have to look for the beginning)
the elements of the main list and smaller lists are strings!
the number of smaller lists depends on the number of '1' in the main list
Basically I need to split a list of strings to smaller lists of strings.
The first idea that came to my mind was to create a ('final') list containing smaller lists, so I created a loop:
List<string> templist = new List<string>();
List<List<string> final = new List<List<string>();
foreach (string log in mainlist)
{
if (log != '1')
{
templist.Add(log);
}
else
{
final.add(templist);
templist.Clear();
templist.Add(log)}
}
final.add(templog);
it seems to work but I get a list with duplicates:
[[1,2,2],[1,2,2],[1,2,2]]

you can do this.
check for 1 and initialize the current list with default item 1 (add the current list to the final list in this step as well)
and if not one then keep on adding the items to the current list.
List<string> currentList = null;
List<string> mainList = new List<string> { "1", "2", "2", "3", "1", "2", "3", "4", "4", "1", "2", "2" };
List<List<string>> finalList = new List<List<string>>();
foreach (string item in mainList)
{
if (item == "1")
{
currentList = new List<string>() { item };
finalList.Add(currentList);
}
else
{
currentList.Add(item);
}
}

Can be:
else
{
templist = new List<string>(){log};
final.add(templist);
}

You can find the index of all occurrences of 1. Then according to these indexes and using the two functions Take() and Skip() to separate the lists..
List<string> mainlist = new List<string>{"1","2","2","3","1","2","3","4","4","1","2","2"};
List<List<string>> final = new List<List<string>>();
var numberOfList = mainlist.Select((item, index) => new {val = item,ind = index})
.Where(item => item.val == "1").ToList();
for(int i = 0; i<numberOfList.Count;i++)
{
if(i == numberOfList.Count-1)
final.Add(mainlist.Skip(numberOfList[i].ind)
.Take(mainlist.Count - numberOfList[i].ind).ToList());
else
final.Add(mainlist.Skip(numberOfList[i].ind)
.Take(numberOfList[i + 1].ind - numberOfList[i].ind).ToList());
}
result:
[1,2,2,3]
[1,2,3,4,4]
[1,2,2]

Related

C# - Determine if all values of a single element in a list of objects are in another list

Currently I am working with something similar to the following:
if(listA.All(x => x.myHouseNumber == "1" || x.myValue == "2")
{
//do something
}
listA is a list of elements (myName, myHouseNumber, myStreet)
basically, I want the condition to be true if every myHouseNumber in listA is found in listB which is just a list of numbers
So if listA contains Bill,1,Main and Ted,2,Second
and listB contains 1,2,3 the condition is true because 1 and 2 are found within list B. if listB contained 1,5,9 the condition would be false because 2 is missing.
I am having trouble understanding how to compare a list with a single item to a single element in a list with several items.
The end result I am hoping would be something like this which I cannot seem to get to work
if(listA.All(x => x.myHouseNumber.Contains(listB.Any())))
{
//do something
}
Hopefully someone will understand what I am going for and be able to provide some assistance
Thanks in advance!
If I understand is correct, you should use the listB contains myHouseNumber.
the demo code.
public class test {
public string myName;
public string myHouseNumber;
public string myStreet;
}
var listA = new List<test>
{ new test { myHouseNumber = "1", myName = "Bill", myStreet = "Main" },
new test { myHouseNumber = "2", myName = "Ted", myStreet = "Second" }
};
var listB = new List<string> { "1", "2", "3" };
var listC = new List<string> { "1", "5", "9" };
// it is true
listA.All(p => listB.Contains(p.myHouseNumber))
// it is false
istA.All(p => listC.Contains(p.myHouseNumber))

Get get part of list after certain value

I have got a simple question I am having a list:
List<string> test = new List<string> {"one", "two", "three", "four"}
Now I want to take for example value "three" and get all elements after it, so it would be looking like:
List<string> test = new List<string> {"three", "four"}
But we do not know where list end so it can be list of many elements and we can not define end as const.
Is it possible?
It sounds like you're looking for SkipWhile from LINQ:
test = test.SkipWhile(x => x != "three").ToList();
That will skip everything until (but not including) the "three" value, then include everything else. It then converts it to a list again.
Since you assign the filtered list back to initial one, then just remove first items up to "three" one:
int count = test.IndexOf("three");
test.RemoveRange(0, count < 0 ? test.Count : count);
This implementation doesn't create additional list, but modifies existing one.
This might do the trick for you
var list2 = test.Skip(2).Take(test.Count).ToList();
or better
var list3 = test.Skip(2).ToList();
Without LINQ it could be done something like this
List<string> outtest = new List<string>();
bool drty = false;
foreach(string st in test)
{
if(st == "three") //or whatever is the input.
drty = true;
if(drty)
outtest.Add(st);
}

find if there is a common string between 2 list of strings using linq

I have two Lists of strings:
List<string> lotterynumber;
List<string> lotterywinningnumber;
I want to see if a lotterynumber is within the lotterywinningnumber.
I am using a foreach loop right now:
bool b = false;
foreach(string s in lotterynumber)
{
if(lotterywinningnumber.contains(s))
{
b= true;
}
}
Is there a way I can do it in Linq?
You can do this using Enumerable.Intersect. It will return a new Enumerable containing the items that exist in both collections.
var lotteryNumbers = new List<string>() { "1", "2", "3" };
var lotteryWinningNumbers = new List<string>() { "2", "3", "5" };
var numbersInBoth = lotteryNumbers.Intersect(lotteryWinningNumbers); // { "2", "3" }
From MSDN:
The intersection of two sets A and B is defined as the set that contains all the elements of A that also appear in B, but no other elements. When the object returned by this method is enumerated, Intersect enumerates first, collecting all distinct elements of that sequence. It then enumerates second, marking those elements that occur in both sequences. Finally, the marked elements are yielded in the order in which they were collected.
The benefit to using Intersect is that it will return the values that exist in both collections, instead of just a Boolean value.
Obviously, if a Boolean value is what you need, you just have to check if the resulting collection contains any elements:
bool contains = lotteryNumbers.Intersect(lotteryWinningNumbers).Any();
There is a way, but the efficiency will be the same: O(n).
Use Any
bool b = lotterynumber.Any(a => lotterywinningnumber.Contains(a));

check whether a List<string> contains an element in another List<string> using LINQ

How do I check whether a List contains an element that exists in another List using LINQ in C#? I don't want to use a for/while loop.
So, if List1 has A, B, C and List2 has B, 1, 2, then I would return true.
Try this:
List<string> a = ...
List<string> b = ...
var inComon = a.Intersect(b).Any();
Use Enumerable.Any Method:
List<string> l1 = new List<string> { "1", "2" };
List<string> l2 = new List<string> { "1", "3" };
var result = l2.Any(s => l1.Contains(s));
I'd say the Intersect method (see answer by dasblinkenlight) + Any must work better than Contains + Any. It is definetely better to use Any than Count.

Finding differences in two lists

I am thinking about a good way to find differences in two lists
here is the problem:
Two lists have some strings where first 3 numbers/characters (*delimited) represent the unique key(followed by the text String="key1*key2*key3*text").
here is the string example:
AA1*1D*4*The quick brown fox*****CC*3456321234543~
where "*AA1*1D*4*" is a unique key
List1: "index1*index2*index3", "index2*index2*index3", "index3*index2*index3"
List2: "index2*index2*index3", "index1*index2*index3", "index3*index2*index3", "index4*index2*index3"
I need to match indexes in both lists and compare them.
If all 3 indexes from 1 list match 3 indexes from another list, I need to track both string entries in the new list
If there is a set of indexes in one list that don't appear in another, I need to track one side and keep an empty entry in another side. (#4 in the example above)
return the list
This is what I did so far, but I am kind of struggling here:
List<String> Base = baseListCopy.Except(resultListCopy, StringComparer.InvariantCultureIgnoreCase).ToList(); //Keep unique values(keep differences in lists)
List<String> Result = resultListCopy.Except(baseListCopy, StringComparer.InvariantCultureIgnoreCase).ToList(); //Keep unique values (keep differences in lists)
List<String[]> blocksComparison = new List<String[]>(); //we container for non-matching blocks; so we could output them later
//if both reports have same amount of blocks
if ((Result.Count > 0 || Base.Count > 0) && (Result.Count == Base.Count))
{
foreach (String S in Result)
{
String[] sArr = S.Split('*');
foreach (String B in Base)
{
String[] bArr = B.Split('*');
if (sArr[0].Equals(bArr[0]) && sArr[1].Equals(bArr[1]) && sArr[2].Equals(bArr[2]) && sArr[3].Equals(bArr[3]))
{
String[] NA = new String[2]; //keep results
NA[0] = B; //[0] for base
NA[1] = S; //[1] for result
blocksComparison.Add(NA);
break;
}
}
}
}
could you suggest a good algorithm for this process?
Thank you
You can use a HashSet.
Create a HashSet for List1. remember index1*index2*index3 is diffrent from index3*index2*index1.
Now iterate through second list.
Create Hashset for List1.
foreach(string in list2)
{
if(hashset contains string)
//Add it to the new list.
}
If I understand your question correctly, you'd like to be able to compare the elements by their "key" prefix, instead by the whole string content. If so, implementing a custom equality comparer will allow you to easily leverage the LINQ set algorithms.
This program...
class EqCmp : IEqualityComparer<string> {
public bool Equals(string x, string y) {
return GetKey(x).SequenceEqual(GetKey(y));
}
public int GetHashCode(string obj) {
// Using Sum could cause OverflowException.
return GetKey(obj).Aggregate(0, (sum, subkey) => sum + subkey.GetHashCode());
}
static IEnumerable<string> GetKey(string line) {
// If we just split to 3 strings, the last one could exceed the key, so we split to 4.
// This is not the most efficient way, but is simple.
return line.Split(new[] { '*' }, 4).Take(3);
}
}
class Program {
static void Main(string[] args) {
var l1 = new List<string> {
"index1*index1*index1*some text",
"index1*index1*index2*some text ** test test test",
"index1*index2*index1*some text",
"index1*index2*index2*some text",
"index2*index1*index1*some text"
};
var l2 = new List<string> {
"index1*index1*index2*some text ** test test test",
"index2*index1*index1*some text",
"index2*index1*index2*some text"
};
var eq = new EqCmp();
Console.WriteLine("Elements that are both in l1 and l2:");
foreach (var line in l1.Intersect(l2, eq))
Console.WriteLine(line);
Console.WriteLine("\nElements that are in l1 but not in l2:");
foreach (var line in l1.Except(l2, eq))
Console.WriteLine(line);
// Etc...
}
}
...prints the following result:
Elements that are both in l1 and l2:
index1*index1*index2*some text ** test test test
index2*index1*index1*some text
Elements that are in l1 but not in l2:
index1*index1*index1*some text
index1*index2*index1*some text
index1*index2*index2*some text
List one = new List();
List two = new List();
List three = new List();
HashMap<String,Integer> intersect = new HashMap<String,Integer>();
for(one: String index)
{
intersect.put(index.next,intersect.get(index.next) + 1);
}
for(two: String index)
{
if(intersect.containsKey(index.next))
{
three.add(index.next);
}
}

Categories