Reputation: 503
I'm using the following piece of code to load my text file into a HashSet<string>
.
HashSet<string> hashs = new HashSet<string>(File.ReadLines("textFile.txt"));
Am wondering if there is any easy way to get a random line from it?
Lets assume the textFile.txt contains 10 lines, I would like to randomize and grab one of those existing lines.
Upvotes: 14
Views: 30950
Reputation: 547
If you are planning on drawing multiple random values, the efficient way would be to use a Dictionary with integer keys to store the information.
HashSet<string> hashs = new HashSet<string>();
Dictionary<int, string> lookup = new Dictionary<int, string>();
foreach (string line in File.ReadLines("textFile.txt")) {
if (hashs.Add(line)) {
lookup.Add(lookup.Count, line);
}
}
int randomInt = new Random().Next(lookup.Count);
string randomLine = lookup[randomInt];
(In this example, you could use a List instead, but with a dictionary you can also remove individual elements without affecting the order).
Upvotes: 0
Reputation: 384
Since .Net Framework 3.5 you can use Linq with its Enumerable.First()
extension method.
Without specifying any condition as parameter this method will return
the first element of a sequence.
You should consider that using Enumerable.First()
requires your HashSet<>
to contain at least one element.
To check this precondition you could either use HashSet<>.Count
or via Linq with Enumerable.Any()
again without specifying a condidion.
HashSet<T> hashSet = new HashSet<T>();
...
if(hashSet.Any())
{
T randomElement = hashSet.First()
}
As an alternative to the approach above you could use Enumerable.FirstOrDefault()
if you would like to retrieve any default value in case the HashSet<T>
is empty.
T randomElement = hashSet.FirstOrDefault(default(T));
Upvotes: -2
Reputation: 2785
a simple answer like the accepted one is possible without enumerating the entire array every time:
private static readonly Random random = new Random();
private static readonly HashSet<T> hashset = new HashSet<T>();
...
T element = hashset.ElementAt(random.Next(hashset.Count));
Upvotes: 40
Reputation: 5333
Or maybe a more general solution for any enumerable
public static class RandomExtensions
{
private static readonly Random rnd = new Random();
private static readonly object sync = new object();
public static T RandomElement<T>(this IEnumerable<T> enumerable) {
if (enumerable == null)
throw new ArgumentNullException("enumerable");
var count = enumerable.Count();
var ndx = 0;
lock (sync)
ndx = rnd.Next(count); // returns non-negative number less than max
return enumerable.ElementAt(ndx);
}
}
Upvotes: 1
Reputation: 648
Random randomizer = new Random();
string[] asArray = hashs.ToArray()
string randomLine = asArray[randomizer.Next(asArray.length)];
Upvotes: 17
Reputation: 28782
You can generate a random number between 0 and the size of the set, then iterate through the set up until you reach the item whose index is the same as the generated number. Then select this item as the random element
Upvotes: 3