Wybranie określonej ilości danych z kolekcji

0

Mam kolekcję powiedzmy 10 000 elementów.
Muszę wybrać z niej powiedzmy 5000 elementów.
Nie wiem dokładnie jak to opisać ale chodzi o to by nie było to pierwsze 5000 ani bardzo losowe (bo losowo też może teoretycznie wybrać te 5000 pierwszych).
Chciałbym by dla kolekcji np 10 elementów, wybranych 5 elementów było: [0,2,5,7,10].
Chodzi o takie jakby uśrednianie danych gdzie mam 10 000 danych ale mogę wyświetlić tylko 5000 więc potrzebuję opuszczać np co drugi. Nie wiem ile danych będzie w sumie w kolekcji ale wiem, że zawsze będę wybierał te 5000. Jeśli kolekcja będzie mniejsza niż 5000 oczywiście wybrane muszę być wszystkie elementy.

Nie wiem jak się do tego zabrać w miarę najwydajniej.
Myślałem o czymś w rodzaju
a) biorę pierwszy i ostatni element
b) znajduję środek kolekcji (czyli mam już 3 elementy) i kolekcję mam podzieloną teraz na 2
c) biorę środek z pierwszej części, biorę środek z drugiej części (mam juz 5 elementów) i kolekcję na 4 części
d) itd.

Ale dla kolekcji kilkudziesięciu elementów takie coś będzie raczej wolne...
Może ktoś pomóc jak się do tego zabrać?
Może być pseudokod, opis idei, cokolwiek.

0

może po prostu podziel ilość elementów kolekcji przez ilość elementów jaką chcesz wypisać?

0

;-) ja też nie bardzo rozumiem problem.
Tzn nie zrozumiałem co chcesz osiągnąć.

Nie możesz pobrać np. co drugi? trzeci... czwarty... itd?

Może podaj więcej szczegółów, albo co konkretnie chcesz uzyskać.
Albo jeszcze jeden przykład ;-)

0
byku_guzio napisał(a):

może po prostu podziel ilość elementów kolekcji przez ilość elementów jaką chcesz wypisać?

zrobiłem coś takiego:


if (collection.Count() < maxCount
                return collection;

IList<MyData> chosen = new List<MyData>();
double step = Math.Round( Convert.ToDouble(collection.Count()) / maxCount );
            for (int i = 0; i < collection.Count(); i++)
            { 
                if(i%step == 0)
                {
                    chosen.Add(collection.ElementAt(i));
                }
            }

            return chosen;

ale dla danych
maxCount = 2000;
collection.Count() = 7913
wychodzi mi, że collection.Count()/ maxCount = 3.9
no więc zaokrąglam w dół lub w górę. W dół otrzymam ponad 2000 elementów, w górę z kolei 1979. A ja muszę mieć równo 2000 jeśli da się tyle wyciągnać

CS mogę oczywiście, jeśli wiem ile elementów mam w kolekcji i ile bede wybierał. Niestety to pierwsze nie jest stałe i ten "krok" muszę znaleźć dynamicznie.

0

nie zaokrąglasz kroku, tylko wynik jego sumy

float index = 0;
while(index < numElements) {
   chosen.Add(collection.ElementAt(floor(index)));
   index += step;
}
0
Mr Obvious napisał(a):

nie zaokrąglasz kroku, tylko wynik jego sumy

float index = 0;
while(index < numElements) {
   chosen.Add(collection.ElementAt(floor(index)));
   index += step;
}

Dla ww danych wybrano 506 elementów...

1
using System;
using System.Collections.Generic;
using System.Linq;

static class EnumerableExtension
{
    public static IEnumerable<T> TakeSome<T>(this IEnumerable<T> all, int number)
    {
        if (number < 0)
            throw new ArgumentOutOfRangeException("number");
        if (number == 0)
            yield break;
        List<T> list = all.ToList();
        if (number >= list.Count)
        {
            foreach (T t in list)
                yield return t;
            yield break;
        }
        if (number == 1)
        {
            yield return list[list.Count / 2];
            yield break;
        }
        double step = (float)(list.Count - 1) / (number - 1);
        double current = 0;
        do
        {
            yield return list[(int)Math.Round(current)];
            current += step;
        }
        while ((int)Math.Round(current) < list.Count - 1);
        yield return list[(int)Math.Round(current)];
    }
}

class Program
{
    static void Main()
    {
        var test = new List<string> {"raz","dwa","trzy","cztery","pięć"};

        foreach (var s in test.TakeSome(3)) // 3 z 5
            Console.WriteLine(s);
    }
}
raz
trzy
pięć
0
CSharper napisał(a):

Dla ww danych wybrano 506 elementów...

Bo tam był drobny błąd,
w linqPadzie po poprawkach działa tak jak chciałeś:

            Collection<int> chosen = new Collection<int>();
            float index = 0;
            int maxElements = 7485;
            int numElements = 500;
            float step = maxElements / numElements;
			int i=0;          
			while (i < numElements)
            {
                chosen.Add((int) Math.Floor(index));
                index += step;
				i++;
            }
			chosen.Dump();
 

1 użytkowników online, w tym zalogowanych: 0, gości: 1