3

Here is my sentence:

You ask your questions on StackOverFlow.com

Now I have a Dictionary collection of List of strings:

Dictionary<int, List<string>> collections = new Dictionary<int, List<string>>()
{
    { 1, new List<string>() { "You", "your" } },
    { 2, new List<string>() { "Stack", "Flow" } },
};

I need to split my string into a list of the string where the strings in the collection are not there and put each List key in its place so I know from which list I'm finding the list's item:

for example, the output of my sentence is:

"1", " ask ", "1", " questions on ", "2", "Over", "2", ".com"

as you can see all of the words in the collection are not listed here. Instead, their list's key is replaced. All I know is that I can check if my string contains any words of another list or not by this code:

listOfStrings.Any(s=>myString.Contains(s));

But do not know how to check an entire dictionary collection of lists and get each list key and replace it in the new list of strings.

Inside Man
  • 4,194
  • 12
  • 59
  • 119
  • 1
    [`String.Split(String[], Int32, StringSplitOptions)`](https://msdn.microsoft.com/fr-fr/library/1bwe3zdy(v=vs.110).aspx) - then you'd need to flatten your `collections` to a unique array and here you go – Rafalon May 17 '18 at 07:29
  • @Rafalon - and how would you split StackOverFlow into Stack,Over,Flow ? – bommelding May 17 '18 at 07:36
  • @bommelding [this way](http://tpcg.io/dEP1Ul) – Rafalon May 17 '18 at 07:41
  • 1
    You shouldn't update your question with more questions, if you wanted to expand your question you should have created a new one. Now all existing answers are invalid... – Jerodev May 17 '18 at 13:31

4 Answers4

2
static void Main()
{
    string myString = "You ask your questions on StackOverFlow.com";
    string[] collection = new string[]
    {
        "You",
        "your",
        "Stack",
        "Flow"
    };

    var splitted = myString.Split(collection, StringSplitOptions.RemoveEmptyEntries);

    foreach(var s in splitted)
    {
        Console.WriteLine("\""+s+"\"");
    }
}

will result in:

" ask "
" questions on "
"Over"
".com"

You can use SelectMany to flatten your collections


Based on your edit:

static void Main()
{
    string myString = "You ask your questions on StackOverFlow.com";

    Dictionary<int, List<string>> collections = new Dictionary<int, List<string>>()
    {
        { 1, new List<string>() { "You", "your" } },
        { 2, new List<string>() { "Stack", "Flow" } },
    };

    foreach(var index in collections.Keys)
    {
        foreach(var str in collections[index])
        {
            myString = myString.Replace(str, index.ToString());
        }
    }

    Console.WriteLine(myString);
}

Gives:

1 ask 1 questions on 2Over2.com

static void Main()
{
    string myString = "You ask your questions on StackOverFlow.com";

    Dictionary<int, List<string>> collections = new Dictionary<int, List<string>>()
    {
        { 1, new List<string>() { "You", "your" } },
        { 2, new List<string>() { "Stack", "Flow" } },
    };

    var tempColl = collections.SelectMany(c => c.Value);
    // { "You", "your", "Stack", "Flow" }

    string separator = String.Join("|", tempColl);
    // "You|your|Stack|Flow"

    var splitted = Regex.Split(myString, @"("+separator+")");
    // { "", "You", " ask ", "your", " questions on ", "Stack", "Over", "Flow", ".com" }

    for(int i=0;i<splitted.Length;i++)
    {
        foreach(var index in collections.Keys)
        {
            foreach(var str in collections[index])
            {
                splitted[i] = splitted[i].Replace(str, index.ToString());
            }
        }
    }

    foreach(var s in splitted)
    {
        Console.WriteLine("\""+s+"\"");
    }
}

Gives:

""
"1"
" ask "
"1"
" questions on "
"2"
"Over"
"2"
".com"

Note the empty string at the beginning is because

If a match is found at the beginning or the end of the input string, an empty string is included at the beginning or the end of the returned array.

But you can easily remove it using either .Where(s => !string.IsNullOrEmpty(s)) or anything alike.

Rafalon
  • 4,450
  • 2
  • 16
  • 30
  • @Nofuzy I updated my answer based on your updated question – Rafalon May 17 '18 at 12:55
  • your updated answer will generate a single string but I need a list of separated strings. How to fix it? – Inside Man May 17 '18 at 14:52
  • @Nofuzy Maybe you could use [`Regex.Split(yourString, @"(?=separators)")`](https://stackoverflow.com/a/5706482/7831383) - with `separators` being `String.Join(collections[index], "|")` based on Conrad Clark's comment. You would then need to iterate through your array to replace the matching strings with their respective value. I'll edit my answer tomorrow to include that – Rafalon May 17 '18 at 20:59
  • @Nofuzy It would be a pleasure, but I am not really willing to give away my mail to everyone as I receive quite enough spam already, so if you have a way I could give it to you, then very well – Rafalon May 21 '18 at 09:32
2

You can flatten the list using the SelectMany linq function. This new list of strings can be fed to the Split function.

var str = "You ask your questions on StackOverFlow.com";
var collections = new[]
{
    new List<string> { "You", "your" },
    new List<string> { "Stack", "Flow" },
};

var values = str.Split(
    collections.SelectMany(s => s).Distinct().ToArray(), 
    StringSplitOptions.RemoveEmptyEntries
);

Console.WriteLine(
    string.Join(", ", values)
);

The code above results in

ask , questions on , Over, .com

Jerodev
  • 32,252
  • 11
  • 87
  • 108
  • 1
    You shouldn't update your question with more questions, if you wanted to expand your question you should have created a new one. Now all existing answers are invalid... – Jerodev May 17 '18 at 13:31
2

You can flatten your collection with linq:

var collections = new[]{
    new List<string> { "You", "your" },
    new List<string> { "Stack", "Flow" },
};

var target = "You ask your questions on StackOverFlow.com";

var splitparts = collections.SelectMany(list => list.Select(s => s)).Distinct().ToArray();

var result = target.Split(splitparts,StringSplitOptions.RemoveEmptyEntries);

which results in the desired

" ask ", " questions on ", "Over", ".com"

The Distinct() part removes dublicates from your collection.

Turbofant
  • 517
  • 11
  • 24
1

But do not know how to check an entire collection of lists.

My reading of your problem is that you're having trouble with "collections of collections". While others are showing how to condense a collection of lists into a single list, being able to search through nested collections is a super useful skill. I present this in that spirit.

        var myString = "You ask your questions on StackOverFlow.com";

        var collections = new[]
        {
            new List<string> { "You", "your" },
            new List<string> { "Stack", "Flow" },
        };

        foreach (var listOfStrings in collections)
        {
            foreach (var word in listOfStrings)
            {
                Console.WriteLine(myString.Contains(word) ? "Yes on " + word : "No on " + word);
            }
        }

I'm just outputting "yes" or "no" on matches, but you could remove them from a string, or replace them with other strings, or whatever transformation you want to do. I'm mostly interested in showing how to loop through a collection[] of List, based on the wording of your question.

christopherdrum
  • 1,513
  • 9
  • 25