Replace all occurences of a string from a string array - c#

I have a string array like:
string [] items = {"one","two","three","one","two","one"};
I would like to replace all ones with zero at once.
Then items should be:
{"zero","two","three","zero","two","zero"};
I found one solution How do I replace an item in a string array?.
But it will replace the first occurrence only. Which is the best method/approach to replace all occurrences?

Theres no way to do that without looping.. even something like this loops internally:
string [] items = {"one","two","three","one","two","one"};
string[] items2 = items.Select(x => x.Replace("one", "zero")).ToArray();
I'm not sure why your requirement is that you can't loop.. however, it will always need to loop.

There is one way to replace it without looping through each element:
string [] items = {"zero","two","three","zero","two","zero"};
Other than that, you have to iterate through the array (for/lambda/foreach)

Sorry, you have to loop. There's no getting around it.
Also, all of the other answers give you a new array with the desired elements. If you want the same array to have its elements modified, as your question implies, you should just do it like this.
for (int index = 0; index < items.Length; index++)
if (items[index] == "one")
items[index] = "zero";
Simple.
To avoid writing a loop in your code every time you need this to happen, create a method:
void ReplaceAll(string[] items, string oldValue, string newValue)
{
for (int index = 0; index < items.Length; index++)
if (items[index] == oldValue)
items[index] = newValue;
}
Then call it like this:
ReplaceAll(items, "one", "zero");
You can also make it into an extension method:
static class ArrayExtensions
{
public static void ReplaceAll(this string[] items, string oldValue, string newValue)
{
for (int index = 0; index < items.Length; index++)
if (items[index] == oldValue)
items[index] = newValue;
}
}
Then you can call it like this:
items.ReplaceAll("one", "zero");
While you're at it, you might want to make it generic:
static class ArrayExtensions
{
public static void ReplaceAll<T>(this T[] items, T oldValue, T newValue)
{
for (int index = 0; index < items.Length; index++)
if (items[index].Equals(oldValue))
items[index] = newValue;
}
}
The call site looks the same.
Now, none of these approaches supports custom string equality checking. For example, you might want the comparison to be case sensitive, or not. Add an overload that takes an IEqualityComparer<T>, so you can supply the comparison you like; this is much more flexible, whether T is string or something else:
static class ArrayExtensions
{
public static void ReplaceAll<T>(this T[] items, T oldValue, T newValue)
{
items.ReplaceAll(oldValue, newValue, EqualityComparer<T>.Default);
}
public static void ReplaceAll<T>(this T[] items, T oldValue, T newValue, IEqualityComparer<T> comparer)
{
for (int index = 0; index < items.Length; index++)
if (comparer.Equals(items[index], oldValue))
items[index] = newValue;
}
}

You can also do it in parallel:
Parallel.For(0, items.Length,
idx => { if(items[idx] == "one") { item[idx] = "zero"; } });

string [] items = {"one","two","three","one","two","one"};
items = items.Select(s => s!= "one" ? s : "zero").ToArray();
Found answer from here.

You can try this, but I think, It will do looping also.
string [] items = {"one","two","three","one","two","one"};
var str= string.Join(",", items);
var newArray = str.Replace("one","zero").Split(new char[]{','});

string[] items = { "one", "two", "three", "one", "two", "one" };
If you want it the index way as you specified:
int n=0;
while (true)
{
n = Array.IndexOf(items, "one", n);
if (n == -1) break;
items[n] = "zero";
}
But LINQ would be better
var lst = from item in items
select item == "one" ? "zero" : item;

string[] newarry = items.Select(str => { if (str.Equals("one")) str = "zero"; return str; }).ToArray();

Related

Is there a function equivalent to "String.IndexOf(String[])"?

Is there any function that returns the index of the first occurrence of ANY string in a given array like: String.IndexOf(String[])?
or do I need a custom function for it?
For example the below function
"AppleBananaCherry".IndexOf(new[] {"Banana", "Cherry"});
and
"AppleBananaCherry".IndexOf(new[] {"Cherry", "Banana"});
returns 5
There is no prepared function but you can use something like this,
var sample = "AppleBananaCherry";
var input = new[] { "Cherry", "Banana" };
var result = input.Min(x => sample.IndexOf(x));
If sample has not any item of input, it returns -1
This should
public static int IndexOf(this string s, string[] values) {
var found = values
.Select(v => s.IndexOf(v))
.Where(index => index >= 0)
.OrderBy(v => v)
.Take(1)
.ToList();
return found.Count > 0 ? found[0] : -1;
}
EDIT: Removing -1 values
There is no built-in function for that, String.IndexOf() method accepts only single string or char as parameter, but you can write your own extension method, which uses IndexOf for every item in array, like in the following sample. It also should correctly exclude -1 from intermediate result
public static class Ext
{
public static int IndexOf(this string thisString, string[] values)
{
var index = thisString.Length;
var isFound = false;
foreach (var item in values)
{
var itemIndex = thisString.IndexOf(item, StringComparison.InvariantCulture);
if (itemIndex != -1 && itemIndex < index)
{
index = itemIndex;
isFound = true;
}
}
return isFound ? index : -1;
}
}
The usage example
var index = "AppleBananaCherry".IndexOf(new[] {"Banana", "Cherry"}); //returns 5
index = "AppleBananaCherry".IndexOf(new[] { "Cherry", "Banana" }); //returns 5

IComparer for string that checks if x starts with y

I've got an array of strings and I need to get all strings, that start with some 'prefix'. I wanna use Array.BinarySearch(). Is it possible? And how should I write a comparer if so?
No, you cannot use BinarySearch in this case. You could use Enumerable.Where instead:
Dim query = From str In array Where str.StartsWith("prefix")
or with (ugly in VB.NET) method synatx:
query = array.Where(Function(str) str.StartsWith("prefix"))
Edit: whoops, C#
var query = array.Where(s => s.StartsWith("prefix"));
Use ToArray if you want to create a new filtered array.
It's easy to create your own StartsWithComparer:
class StartsWithComparer : IComparer<string>
{
public int Compare(string a, string b) {
if(a.StartsWith(b)) {
return 0;
}
return a.CompareTo(b);
}
}
As others pointed out, this will only return one index. You can have a couple of helpers to return all items:
IEnumerable<string> GetBefore(IList<string> sorted, int foundIndex, string prefix) {
for(var i = foundIndex - 1; i >= 0; i--) {
if(sorted[i].StartsWith(prefix)) {
yield return sorted[i];
}
}
}
IEnumerable<string> GetCurrentAndAfter(IList<string> sorted, int foundIndex, string prefix) {
for(var i = foundIndex; i < sorted.Count; i++) {
if(sorted[i].StartsWith(prefix)) {
yield return sorted[i];
}
}
}
Then to use it:
var index = sorted.BinarySearch("asdf", new StartsWithComparer());
var previous = GetBefore(sorted, index, "asdf");
var currentAndAfter = GetCurrentAndAfter(sorted, index, "asdf");
You can wrap the whole thing in your own class, with a single method that returns all items that start with your prefix.

removing similar string from an array in c#

Suppose i have array of strings as follows:
string[] array = new string[6];
array[0] = "http://www.s8wministries.org/general.php?id=35";
array[1] = "http://www.s8wministries.org/general.php?id=52";
array[2] = "http://www.ecogybiofuels.com/general.php?id=6";
array[3] = "http://www.stjohnsheriff.com/general.php?id=186";
array[4] = "http://www.stjohnsheriff.com/general.php?id=7";
array[5] = "http://www.bickellawfirm.com/general.php?id=1048";
Now I want to store only one similar occurrence of the string ie http://www.s8wministries.org/general.php?id=35 discarding any other string that has http://www.s8wministries.org and store it in another array.
Please how do I go about this?
my attempt is as follows:-
//remove similar string from array storing only one similar in another array
foreach (var olu in array)
{
string findThisString = olu.ToString();
string firstTen = findThisString.Substring(0, 15);
// See if substring is in the table.
int index1 = Array.IndexOf(array, firstTen); //substring is not in table
}
try this with List of string, so you have list of string containing URL, you can use URI class to compare domains:
for(int i = 0; i < strList.Length; i++)
{
Uri uriToCompare = new Uri(strArray[i]);
for(int j = i+1; j < strArray.Length; j++){
Uri uri = new Uri(strArray[j]);
if( uriToCompare.Host == uri.Host){
strList.RemoveAt(j);
}
}
}
Here is how I would approach this
Initialize a hashtable or a dictionary for holding domain names
Loop through each item
Do a string split operation with using '', '.', '/' etc as delimiters - find out the domain by parsing the parts.
Check if the domain name exists in the hashtable. If it does, discard the current entry. If it doesn't exist, insert into the hashtable and also add the current entry to a new list of your selected entries.
Another option would be to sort the entries alphabetically. Go through them one at a time. Select an entry with the domain name. Skip all the next entries with the same domain name. Select the next entry when the domain name changes again.
Let's say the result is to be stored in an array called unique_array and that your current array is called array. Pseudo-code follows:
bool found = false;
for(int i = 0; i < array_size; i++)
{ if(array[i] starts with "http://www.s8wministries.org")
{ if(found) continue;
found = true;
}
add array[i] to end of unique_array;
}
I would go the way of slightly more automation by creating a class that inherits IEqualityComparer (utilizing the great answer to this question):
public class PropertyComparer<T> : IEqualityComparer<T>
{
Func<T, T, bool> comparer;
public PropertyComparer<T>(Func<T, T, bool> comparer)
{
this.comparer = comparer;
}
public bool Equals(T a, T b)
{
return comparer(a, b);
}
public int GetHashCode(T a)
{
return a.GetHashCode();
}
}
Once you have that class - you can use Distinct like this:
var distinctArray = array.Select(s => new Uri(s)).Distinct(new PropertyComparer<Uri>((a, b) => a.Host == b.Host));
That leaves you with an array only containing distinct domains. It's an IEnumerable so you may want to .ToList() it or something, or revert it back to strings from Uris . But I think this method makes for much more readable code.
Please try below Code:
string[] array = new string[6];
array[0] = "http://www.s8wministries.org/general.php?id=35";
array[1] = "http://www.s8wministries.org/general.php?id=52";
array[2] = "http://www.ecogybiofuels.com/general.php?id=6";
array[3] = "http://www.stjohnsheriff.com/general.php?id=186";
array[4] = "http://www.stjohnsheriff.com/general.php?id=7";
array[5] = "http://www.bickellawfirm.com/general.php?id=1048";
var regex = #"http://www.[\w]+.[\w]+";
var distList = new List<string>();
var finalList = new List<string>();
foreach (string str in array)
{
Match match = Regex.Match(str, regex, RegexOptions.IgnoreCase);
if (match.Success)
{
var uniqueUrl = match.Groups[0].Value;
if (!distList.Contains(uniqueUrl))
{
distList.Add(uniqueUrl);
finalList.Add(str);
}
}
}
Here finalList contains the required list of URLs

c# Array.FindAllIndexOf which FindAll IndexOf

I know c# has Array.FindAll and Array.IndexOf.
Is there a Array.FindAllIndexOf which returns int[]?
string[] myarr = new string[] {"s", "f", "s"};
int[] v = myarr.Select((b,i) => b == "s" ? i : -1).Where(i => i != -1).ToArray();
This will return 0, 2
If the value does not exist in the array then it will return a int[0].
make an extension method of it
public static class EM
{
public static int[] FindAllIndexof<T>(this IEnumerable<T> values, T val)
{
return values.Select((b,i) => object.Equals(b, val) ? i : -1).Where(i => i != -1).ToArray();
}
}
and call it like
string[] myarr = new string[] {"s", "f", "s"};
int[] v = myarr.FindAllIndexof("s");
You can write something like :
string[] someItems = { "cat", "dog", "purple elephant", "unicorn" };
var selectedItems = someItems.Select((item, index) => new{
ItemName = item,
Position = index});
or
var Items = someItems.Select((item, index) => new{
ItemName = item,
Position = index}).Where(i => i.ItemName == "purple elephant");
Read : Get the index of a given item using LINQ
Searches for an element that matches the conditions defined by the specified predicate, and returns all the zero-based index of the occurrence within the entire System.Array.
public static int[] FindAllIndex<T>(this T[] array, Predicate<T> match)
{
return array.Select((value, index) => match(value) ? index : -1)
.Where(index => index != -1).ToArray();
}
I know this is an old post, but you can try the following,
string[] cars = {"Volvo", "BMW", "Volvo", "Mazda","BMW","BMW"};
var res = Enumerable.Range(0, cars.Length).Where(i => cars[i] == "BMW").ToList();
returns {1,4,5} as a list
No, there is not. But you can write your own extension method.
public static int[] FindAllIndexOf<T>(this T[] a, Predicate<T> match)
{
T[] subArray = Array.FindAll<T>(a, match);
return (from T item in subArray select Array.IndexOf(a, item)).ToArray();
}
and then, for your array, call it.
You can loop with findIndex giving an index
string[] arr = { "abc", "asd", "def", "abc", "lmn", "wer" };
int index = -1;
do
{
index = Array.IndexOf(arr, "abc", index + 1);
System.Console.WriteLine(index);
} while (-1 != index);
I've used Nikhil Agrawal's answer to create the following related method, which may be useful.
public static List<int> FindAllIndexOf<T>(List<T> values, List<T> matches)
{
// Initialize list
List<int> index = new List<int>();
// For each value in matches get the index and add to the list with indexes
foreach (var match in matches)
{
// Find matches
index.AddRange(values.Select((b, i) => Equals(b, match) ? i : -1).Where(i => i != -1).ToList());
}
return index;
}
Which takes a list with values and a list with values that are to be matched. It returns a list of integers with the index of the matches.
You can solve this problem by creating only 2 integer variables. More power to you!
string[] seasons= { "Fall","Spring", "Summer", "Fall", "Fall", "Winter"};
int i = 0;
int IndexOfFallInArray = 0;
int[] IndexesOfFall= new int[seasons.Length];
foreach (var item in seasons)
{
if (item == "Fall")
{
IndexesOfFall[i] = IndexOfFallInArray;
i++;
}
IndexOfFallInArray++;
}
How about simply:
public static IEnumerable<int> Available()
{
for (int i = 0; i < myarr.Length; i++)
{
if (myarr[i] is null) //Your predicate here...
yield return i;
}
}
I'm aware that the question is answered already, this is just another way of doing it. note that I used ArrayList instead of int[]
// required using directives
using System;
using System.Collections;
String inputString = "The lazy fox couldn't jump, poor fox!";
ArrayList locations = new ArrayList(); // array for found indexes
string[] lineArray = inputString.Split(' '); // inputString to array of strings separated by spaces
int tempInt = 0;
foreach (string element in lineArray)
{
if (element == "fox")
{
locations.Add(tempInt); // tempInt will be the index of current found index and added to Arraylist for further processing
}
tempInt++;
}

How can I access the next value in a collection inside a foreach loop in C#?

I'm working in C# and with a sorted List<T> of structs. I'm trying to iterate through the List and for each iteration I'd like to access the next member of the list. Is there a way to do this?
Pseudocode example:
foreach (Member member in List)
{
Compare(member, member.next);
}
You can't. Use a for instead
for(int i=0; i<list.Count-1; i++)
Compare(list[i], list[i+1]);
You could just keep the previous value instead:
T prev = default(T);
bool first = true;
foreach(T item in list) {
if(first) {
first = false;
} else {
Compare(prev, item);
}
prev = item;
}
If one were so inclined, you could probably write an Extension method for this as well...
public static void ForEachNext<T>(this IList<T> collection, Action<T, T> func)
{
for (int i = 0; i < collection.Count - 1; i++)
func(collection[i], collection[i + 1]);
}
Usage:
List<int> numList = new List<int> { 1, 3, 5, 7, 9, 11, 13, 15 };
numList.ForEachNext((first, second) =>
{
Console.WriteLine(string.Format("{0}, {1}", first, second));
});
Use a regular for loop with an index, and compare list[i] and list[i+1]. (But make sure to only loop until the second-to-last index.)
Or, if you really want to use a foreach, you can keep a Member reference to the previous member and check the next time around. But I wouldn't recommend it.
LINQ might be your friend here. This approach will work with anything that's IEnumerable<T>, not just IList<T> collections, which is very useful if your collection never ends or is otherwise calculated on-the-fly:
class Program {
static void Main(string[] args) {
var list = new List<Int32> { 1, 2, 3, 4, 5 };
foreach (var comparison in list.Zip(list.Skip(1), Compare)) {
Console.WriteLine(comparison);
}
Console.ReadKey();
}
static Int32 Compare(Int32 first, Int32 second) {
return first - second;
}
}
XmlNode root = xdoc.DocumentElement;
XmlNodeList nodeList = root.SelectNodes("descendant::create-backup-sets/new-file-system-backup-set");
for (int j = 0; j < nodeList.Count; j++ )
{
for (int i = 0; i <= nodeList.Item(j).ChildNodes.Count - 1; i++)
{
if (nodeList.Item(j).ChildNodes[i].Name == "basic-set-info")
{
if (nodeList.Item(j).ChildNodes[i].Attributes["name"].Value != null)
{
// retrieve backup name
_bName = nodeList.Item(j).ChildNodes[i].Attributes["name"].Value.ToString();
}
}
You can do it by IndexOf but FYI IndexOf get the first item equal to the item so if you have a lot of items with the same value it's better to use for loop instead or define the range of search. Official docs are here
foreach (Member member in List)
{
var nextItem = List[List.IndexOf(member)+1];
Compare(member, nextItem);
}

Categories