Reputation: 7233
I would like to retrieve the elements from a list that (in consecutive order) match an expression, but for the moment I don't see the (performant) solution.
E.g.:
var items = new List<string>
{
"1",
".",
"249",
"something",
"1", // 5
".", // 6
"250", // 7
"yes"
};
// I am looking for the consecutive elements that form the expression below (5-6-7).
var match = "1.250";
var elements = ...;
Upvotes: 0
Views: 586
Reputation: 1445
Here's a way that's straightforward and isn't nested more than 1 level.
This will find the first match. If no match is found, indexes
will have a count of 0 after the loop. Put inside a method of your choosing.
List<int> indexes = new List<int>();
for (int i = 0; i < items.Count; i++)
{
string temp = items[i];
while (temp.Length < match.Length && temp == match.Substring(0, temp.Length) && i < items.Count - 1)
{
indexes.Add(i + 1); // example was given using 1-based
temp += items[++i];
}
if (temp == match)
{
indexes.Add(i + 1);
break; // at this point, indexes contains the values sought
}
indexes.Clear();
}
With a list of 10,000 elements, where the elements to find are at the end, this runs in about 0.0003775 seconds.
Upvotes: 2
Reputation: 3609
public IEnumerable<int> GetMatch(List<string> items, string match)
{
string str = null;
for (int i = 0; i < items.Count; i++)
{
if (!match.StartsWith(items[i]))
continue;
for (int j = 1; j < items.Count - i + 1; j++)
{
str = items.Skip(i).Take(j).Aggregate((x, y) => x + y);
if (str.Equals(match))
return Enumerable.Range(i + 1, j).Select(x => x).ToList();
else if (match.StartsWith(str))
continue;
break;
}
}
return new int[0];
}
[Fact]
public void Test()
{
var items = new List<string> { "1", ".", "249", "something", "1", ".", "250", "yes" };
var match = "1.250";
var matchingIndexes = GetMatch(items, match);
Assert.True(matchingIndexes.Any());
Assert.Equal(5, matchingIndexes.ElementAt(0));
Assert.Equal(6, matchingIndexes.ElementAt(1));
Assert.Equal(7, matchingIndexes.ElementAt(2));
}
Upvotes: 0
Reputation: 34433
Try IEquatable :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication137
{
class Program
{
static void Main(string[] args)
{
List<string> ipAddresses = new List<string>() {
"172.15.15.1",
"172.15.15.2",
"172.15.15.3",
"172.15.15.4",
"172.16.15.1",
"172.17.15.1"
};
MatchIp matchIP = new MatchIp("172.15", "172.16");
List<string> results = ipAddresses.Where(x => matchIP.Equals(x)).ToList();
}
}
public class MatchIp : IEquatable<string>
{
int[] startAddress { get; set; }
int[] endAddress { get; set; }
int length { get; set; }
public MatchIp(string startAddressStr, string endAddressStr)
{
startAddress = startAddressStr.Split(new char[] { '.' }).Select(x => int.Parse(x)).ToArray();
endAddress = endAddressStr.Split(new char[] { '.' }).Select(x => int.Parse(x)).ToArray();
length = Math.Min(startAddress.Count(), endAddress.Count());
}
public Boolean Equals(string ip)
{
Boolean results = true;
try
{
int[] address = ip.Split(new char[] { '.' }).Select(x => int.Parse(x)).ToArray();
if (address.Length == 4)
{
for (int i = 0; i < length; i++)
{
if ((address[i] < startAddress[i]) || (address[i] > endAddress[i]))
{
results = false;
break;
}
}
}
else
{
results = false;
}
}
catch (Exception ex)
{
results = false;
}
return results;
}
}
}
Upvotes: 0
Reputation: 41
This should give an answer but if there is more than one matches it returns the last one.
public static void GetConsecutiveMatch(List<String> items, String match, out List<int> indices)
{
indices = new List<int>();
for (int i = 0; i < items.Count(); i++)
{
var strToCompare = "";
for (int j = i ; j < items.Count(); j++)
{
strToCompare += items[j];
if (strToCompare.Length == match.Length)
{
if (strToCompare == match)
{
indices.Clear();
for (int k = i; k <= j; k++)
{
indices.Add(k + 1); // at your example indices seems to be starting at 1, so I added 1 to the actual index
}
}
break;
}
else if (strToCompare.Length > match.Length)
{
break;
}
}
}
}
Upvotes: 1