|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Feb 2003
Città: Stockholm (SE)
Messaggi: 1343
|
[C# ma non solo] - Combinare elementi di array
Salve a tutti, causa anche sbornia della sera prima
, mi sto perdendo in un bicchiere d'acqua.Praticamente, dato un array di qualsiasi tipo (per l'esempio diremo string) di lunghezza non nota a priori, Codice:
var strings = new string[] { "a", "b", "c", "d" };
Codice:
a,b a,c a,d b,c b,d c,d a,b,c a,b,d a,c,d b,c,d a,b,c,d Codice:
void Main()
{
var strings = new string[] { "a", "b", "c", "d" };
List<string[]> result = new List<string[]>();
//2
for (int i = 0; i < strings.Length; i++)
{
string a1 = strings[i];
for (int y = i+1; y < strings.Length; y ++)
{
result.Add( new string[]{a1, strings[y]});
}
}
//3
for (int i = 0; i < strings.Length; i++)
{
string a1 = strings[i];
for (int y = i + 1; y < strings.Length; y ++)
{
string a2 = strings[y];
for (int z = y + 1; z < strings.Length; z ++)
{
result.Add(new string[]{a1, a2, strings[z]});
}
}
}
//4
for (int i = 0; i < strings.Length; i++)
{
string a1 = strings[i];
for (int y = i + 1; y < strings.Length; y++)
{
string a2 = strings[y];
for (int z = y + 1; z < strings.Length; z++)
{
string a3 = strings[z];
for (int w = z + 1; w < strings.Length; w++)
{
result.Add(new string[]{a1, a2, a3, strings[w]});
}
}
}
}
result.Dump();
}
Perché dico che l'algoritmo dovrebbe essere generalizzabile? non ho fatto alcuno studio di fattibilitá a riguardo, ma ad occhio non mi sembra impossibile da risolvere... La possibilitá di usare LINQ, ed eventualmente parallelizzare il tutto (con PLINQ o anche solo con i task) sarebbe un plus non invidiabile.... Grazie a tutti =) |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Guarda, la mia ignoranza riguardo a C# e LinqPad non mi consente di esserti di grosso aiuto, ma vedo che il procedimento che stai attuando è più o meno quello di generare l'insieme delle parti dell'insieme originario, ad esclusione però degli elementi che non superano una certa lunghezza.
Quindi un algoritmo in pseudocodice per generare l'insieme delle parti è il seguente: Codice:
algoritmo Insieme-Parti(array di interi A) → array di array di interi
{
S = {∅}; // inizia con un insieme delle parti vuoto
per ogni x ∈ A {
S' = ∅; // crea un insieme temporaneo di appoggio
per ogni I ∈ S {
I' = I ∪ {x}; // estendi il precedente insieme I con il nuovo elemento x
S' = S' ∪ {I'}; // aggiungi il nuovo insieme I' così costruito ad S'
}
S = S ∪ {S'}; // aggiungi tutti gli elementi di S' ad S
}
restituisci S;
}
Fatto questo, puoi fare una scansione lineare di quanto hai ottenuto e rimuovere tutti quegli insiemi che hanno lunghezza minore di 2. Ecco pronto il risultato. ciao
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Feb 2003
Città: Stockholm (SE)
Messaggi: 1343
|
grazie per lo spunto =)
ora devo vedere come togliere alcuni elementi indesiderati (tipo b,a,c,d) |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Feb 2003
Città: Stockholm (SE)
Messaggi: 1343
|
risolto, per ora in maniera sequenziale... purtroppo ogni step é figlio dei risultati dello step i-1 quindi é difficilmente parallelizzabile in quel senso...
Codice:
IEnumerable<T[]> GetParts<T>(T[] items)
{
var container = new List<T[][]>();
container.Add(items.Select(i => new[]{ i }).ToArray());
for (int j = 1; j < items.Length; j++)
{
var parts = new List<T[]>();
var itemsToAdd = items.Skip(j);
for (int i = 0; i < container[j-1].Count(); i++)
{
for (int y = 0; y < itemsToAdd.Count(); y ++)
{
var indexOfLast = Array.IndexOf(items, container[j-1][i].Last());
var indexOfItem = Array.IndexOf(items, itemsToAdd.ElementAt(y));
if (indexOfLast < indexOfItem)
{
var list = new List<T>(container[j-1][i]);
list.Add(itemsToAdd.ElementAt(y));
parts.Add(list.ToArray());
}
}
}
container.Add(parts.ToArray());
}
return container.Skip(1).SelectMany(a => a);
}
|
|
|
|
|
|
#5 |
|
Senior Member
Iscritto dal: Feb 2003
Città: Stockholm (SE)
Messaggi: 1343
|
continuo a cantarmela ed a suonarmela da solo...
ho scritto un programmino per testare le performance della funzione postata sopra anche per lo sfizio di provare ad usare la nuova TPL (Task Parallel Library) in .NET 4 (se vi interessa leggete questo facilissimo tutorial) Ecco il codice di test: Codice:
void Main()
{
List<Task> tasks = new List<Task>();
for (int c = 2; c < 20; c++)
{
int itemsToProcess = c;
var compute = Task.Factory.StartNew(() =>
{
var items = Enumerable.Range(1, itemsToProcess).ToArray();
Stopwatch sw = Stopwatch.StartNew();
GetParts(items);
sw.Stop();
return new Result { ItemsToProcess = itemsToProcess, Elapsed = sw.Elapsed };
});
tasks.Add(compute);
}
var r = Task.Factory.ContinueWhenAll(tasks.ToArray(), results =>
{
DataTable dt = new DataTable("Results");
dt.Columns.Add("Processed items", typeof(int));
dt.Columns.Add("Elapsed time", typeof(TimeSpan));
dt.AcceptChanges();
foreach(var task in results)
{
var result = (task as Task<Result>).Result ;
var row = dt.NewRow();
row.SetField<int>(0, result.ItemsToProcess);
row.SetField<TimeSpan>(1, result.Elapsed);
dt.Rows.Add(row);
row.AcceptChanges();
}
dt.AcceptChanges();
dt.Dump();
});
r.Wait();
}
IEnumerable<T[]> GetParts<T>(T[] items)
{
var container = new List<T[][]>();
container.Add(items.Select(i => new[]{ i }).ToArray());
for (int j = 1; j < items.Length; j++)
{
var parts = new List<T[]>();
var itemsToAdd = items.Skip(j);
for (int i = 0; i < container[j-1].Count(); i++)
{
for (int y = 0; y < itemsToAdd.Count(); y ++)
{
var indexOfLast = Array.IndexOf(items, container[j-1][i].Last());
var indexOfItem = Array.IndexOf(items, itemsToAdd.ElementAt(y));
if (indexOfLast < indexOfItem)
{
var list = new List<T>(container[j-1][i]);
list.Add(itemsToAdd.ElementAt(y));
parts.Add(list.ToArray());
}
}
}
container.Add(parts.ToArray());
}
return container.Skip(1).SelectMany(a => a);
}
class Result
{
public int ItemsToProcess { get; set; }
public TimeSpan Elapsed { get; set; }
}
Codice:
Processed items Elapsed time 02 00:00:00.0051974 03 00:00:00.0753525 04 00:00:00.0746062 05 00:00:00.0468833 06 00:00:00.0147504 07 00:00:00.0462238 08 00:00:00.0771023 09 00:00:00.0907102 10 00:00:00.0672947 11 00:00:00.0307465 12 00:00:00.0631659 13 00:00:00.1878733 14 00:00:00.4249925 15 00:00:00.9270264 16 00:00:01.7154481 17 00:00:02.9197939 18 00:00:05.2214003 19 00:00:10.2407435 non a caso, studiando i tempi dei casi piú comuni (da 2 a 5 elementi) si hanno tempi che sono diversi da quelli postati prima. Codice:
2 00:00:00.0050126 3 00:00:00.0049253 4 00:00:00.0044408 5 00:00:00.0050880 Ultima modifica di Kralizek : 03-09-2010 alle 15:52. |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 06:57.










, mi sto perdendo in un bicchiere d'acqua.








