Scripting - Összes lehetőség több tömböt keverve változó mérettel és egy tömb több elemével

Sziasztok,

Elsősorban PowerShell-ben szeretném megoldani az alábbi feladatot - de lassan ott járok bármi jó lesz:

Adottak:
tömb1: { "Egyes", "Kettes", "Hármas", "Négyes", "Ötös" }
tömb2: { "Alma", "Körte", "Dinnye" }
tömb3: { "Virág", "Kert", "Ásó", "Szilva", "Tök" }
tömb4: { "Valami", "Valami2", "Valami3" }

- Amint látható, mind a négy tömb változó méretű
- mind string lesz egyébként
- Term. nem ezekkel az adatokkal, ékezetekkel és változónevekkel persze.

A kérdés amit meg szeretnék oldani:
- Létrehozni egy n elemű tömböt, amely tömb mindegyik tömb legalább egy elemét a fentinek tartalmazza, de tömb3 elemei többször is szerepelhetnek.

Tehát pl. lehetséges az, hogy az egyik megoldás: { "Egyes", "Dinnye", "Virág", "Kert", "Tök", "Valami2" } - azaz csak a tömb3 elemei szerepelhetnek többször mint 1, a többi csak egyszer, de legalább egyszer szerepelj.

A C#-ban rátaláltam én a CartesianProduct class definíciójára, néztem is már, de kissé vakartam a fejem a feltétel és a nem egyező méret miatt

Valakinek van-e erre ötlete?

Hozzászólások

Nos egy olyan tömböt (listát) szeretnék létrehozni ami az összes lehetőséget permutációként tartalmazza, amit írtál az egyenként kiírja ugyan az eredményt de valamelyest ennél pragmatikusabban oldanám meg a feladatot.

Küldök egy kódrészletet amiben a több tömb permutálására egy jó példát hozott a CartesianProduct class és ahogy említettem felhasználtam C#-ban a példa illusztrálására.

Ezzel csak az a baj, hogy ez minden elemet egyszer használ fel, tehát a harmadik elemek csak egyszer kerülnek bele. Persze ennyi elemnél kézzel megcsinálhatnám az összes lehetőséget, az elég csúnya megoldás lenne.

Ráadásul ez a CartesianProduct C#-ban van és bár a .NET libeket lehet használni PowerShell alatt, megnehezítené a dolgokat ha forrást kéne buildezni és követni mondjuk hogy melyik VS-el buildezte az ember, stb., ennyiből jóval egyszerűbb lenne PSben.

Kód:

static void Main(string[] args)
{
var full = new CartesianProduct(
new string[] { "Egyes", "Kettes", "Harmas", "Negyes", "Otos", "Hatos"}
, new string[] { "Alma", "Korte", "Dinnye", "Cseresznye", "Szolo" }
, new string[] { "Virag", "Kert", "Aso", "Szilva", "Tok" }
, new string[] { "Valami", "Valami2", "Valami3" }
);
foreach (var i in full.Get())
{
List possibles = new List();
possibles.Add(i[0]);
possibles.Add(i[1]);
possibles.Add(i[2]);
possibles.Add(i[3]);
var possiblesArray = possibles.ToArray();
foreach (string c in possiblesArray)
{
Console.Write(c.ToString());
Console.Write(" ");
}
Console.WriteLine();
}
Console.ReadLine();
}
}

A CartesianProduct:

public class CartesianProduct
{
int[] lengths;
T[][] arrays;
public CartesianProduct(params T[][] arrays)
{
lengths = arrays.Select(k => k.Length).ToArray();
if (lengths.Any(l => l == 0))
throw new ArgumentException("Zero lenght array unhandled.");
this.arrays = arrays;
}

public IEnumerable Get()
{
int[] walk = new int[arrays.Length];
int x = 0;
yield return walk.Select(k => arrays[x++][k]).ToArray();
while (Next(walk))
{
x = 0;
yield return walk.Select(k => arrays[x++][k]).ToArray();
}
}

private bool Next(int[] walk)
{
int whoIncrement = 0;
while (whoIncrement < walk.Length)
{
if (walk[whoIncrement] < lengths[whoIncrement] - 1)
{
walk[whoIncrement]++;
return true;
}
else
{
walk[whoIncrement] = 0;
whoIncrement++;
}
}
return false;
}
}

"Létrehozni egy n elemű tömböt, amely tömb mindegyik tömb legalább egy elemét a fentinek tartalmazza, de tömb3 elemei többször is szerepelhetnek."
Íme:


PS > $tömb1[0], $tömb2[0], $tömb3[0], $tömb4[0]
Egyes
Alma
Virág
Valami
PS >

Szerintem pontosítsd, mit szeretnél, mert ez pontosan megfelel annak, amit kértél, de aligha ez volt a fejedben a feladvány.

Ez például véletlenszerűen állít elő egy, a fenti feltételeknek megfelelő tömböt:


(Get-Random -InputObject $tömb1),  (Get-Random -InputObject $tömb2),  (Get-Random -InputObject $tömb3 -Count (Get-Random -Minimum 1 -Maximum $tömb3.Count)),  (Get-Random -InputObject $tömb4)

Üdv,
Marci

Ezt keresed?


Function Generate-Subsets ($set)
{
  $subsets=@()
  for ($i=1;$i -lt [math]::pow(2,$set.Count);$i++)
  {
    $mask=[convert]::ToString($i,2)
    $ss=@()
    for ($j=0;$j -lt $mask.Length;$j++)
    {
      if ($mask[$j] -eq "1") 
      {
        $ss+=$set[$mask.Length-$j-1]
      }
    }
    $subsets+=,$ss
  }
  return $subsets
}

$tömb1= "Egyes", "Kettes", "Hármas", "Négyes", "Ötös"
$tömb2= "Alma", "Körte", "Dinnye" 
$tömb3= "Virág", "Kert", "Ásó", "Szilva", "Tök" 
$tömb4= "Valami", "Valami2", "Valami3" 
foreach ($i1 in $tömb1)
{
    foreach ($i2 in $tömb2)
    {
       foreach ($i3 in Generate-Subsets($tömb3))
       {
         foreach ($i4 in $tömb4)
         {
            $items=$i3
            $items+=$i1,$i2,$i4
            $items -join ","
         }
       }

    }
}

Üdv,
Marci

Szia!

Igen, erre gondoltam, ez egy jó megoldás, bár most épp azon szórakozom hogy na és akkor ezt hogyan rendezem mondjuk $tömb1 alapján, mivelhogy a $tömb3 néha 2, vagy akár 3 elem is lehet, nem mondhatom hogy akkor mindig rendezem a $item-et 2. elem alapján, mivel néha a 2. az épp tömb3-nak lesz egyik permutációja.

Arra gondoltam, hogy megszámolhatnám hogy hány elemű a subset előbb, majd utána a megfelelő column-ra hivatkoznék, ami mondjuk mindig igaz lesz hogy +1 mint ahány elemű a $tömb3 subset-je. Hmm?

Köszi a segítséget, sikerült megoldanom.

A kód alapján amit küldtél, a rendezési elv $i4 alapján történt volna. Minekutána $i3 viszont több értéket is felvehet, $items[1] vagy $items[2] stb. nem minden esetben stimmelt volna, amire a rendezés épülhetne - ezért ahogy ötleteltem, gyakorlatilag külön függvénybe tettem a subset generálást ami visszaadja azt a subset-et amit $i3-ból készítünk először; ennek a returned value-nak megmértem a hosszát (mondjuk legyen ez $pLength) és gyakorlatilag ahhoz igazítom dinamikusan hogy $items[$pLength] hogy hol helyezkedik el $i3.

Ezzel rendeztem $i3 alapján így:
$blah = $items[$pLength]

majd amikor kiírom, ennyit adtam hozzá - a vesszőt a későbbi file-ba kiírt elemzés miatt három pipe-ra cseréltem.

$items -join " ||| " | Sort | ForEach-Object{$blah + " " + $_}

Ha érdekel szívesen elküldöm az egészet!

Nagyon egyszerű.
Mivel csak a tömb3 többelemű, ezért:
- tömb1 alapján rendezi: az első elem szerint rendezni.
- tömb2 alapján rendezni: a második elem szerint rendezni
- tömb3 alapján rendezni: a harmadiktól utolsó előtti elem szerint rendezni
- tömb4 alapján rendezni: az utolsó elem szerint rendezni

Mindig pontosan definiált, hogy melyik elem melyik tömbből jön.