How can I replace a set of Nested For Loops with a Functional Code Alternative?
Update: A faster alternative:
foo = Boole @* LessThan[4] @* Length @* Union @* Transpose @*
Developer`ToPackedArray @* List;
c0 = Outer[foo, mt, mt, 1];
c0 == c
True
Original answer:
mt = Transpose[m];
c1 = Boole @ Outer[Length@Union@Transpose[{##}] < 4 &, mt, mt, 1];
c1 == c
True
Alternatively,
mt = Transpose[m];
c2 = ConstantArray[0, {32, 32}];
Do[c2[[i, j]] = c2[[j, i]] = Boole[Length@Union[Transpose[{mt[[i]], mt[[j]]}]] < 4],
{i, 1, Length @ columnlabels}, {j, 1, i}];
c2 == c
True
and
mt = Transpose[m];
c3 = SparseArray[{i_, j_} :>
Boole[Length@Union[Transpose[{mt[[ i]], mt[[j]]}]] < 4],
{1, 1} Length[columnlabels]]
Normal[c3] == c
True
and
mt = Transpose[m];
c4 = SymmetrizedArray[{i_, j_} :>
Boole[Length@Union@Transpose[{mt[[ i]], mt[[j]]}] < 4],
{1, 1} Length[columnlabels], Symmetric[{1, 2}]]
Normal[c4] == c
True
Using Table instead of For.
SeedRandom[99]
dat1 = Table[Table[RandomInteger[8], {6}], {6}];
dat2 = Table[Tally[dat1[[i]][[All]]], {i, 1, 6}];
wrapFn[x_List, yLimit_Integer] :=
If[Length[x] < yLimit, 100, 0]
datOut = Table[wrapFn[dat2[[i]], 5], {i, 1, 6}]
(* Out: {100, 0, 100, 100, 100, 0} *)
Just if it helps the OP, with a pre-Fortran IV mind like myself? The O[?] is probably worse than the checked answer.
New Way:
SeedRandom[99]
dat3 = RandomInteger[8, {6, 6}]
dat4 = Map[Tally, dat3]
dat5Out = Map[If[Length[#] < 5, 100, 0] &, dat4]
(* Out: {100,0,100,100,100,0} *)
An improved version of kglr's answer, makes use of the fact that m
only consists of 0
and 1
:
m = RandomInteger[{0, 1}, {31, 2754}];
mt = Transpose[m];
func = Composition[Length, Union, Plus];
c2 = 1 - (Outer[func, mt, 2 mt, 1] - 4 // UnitStep); // AbsoluteTiming
(* {22.1601, Null} *)
kglr's solution takes about 53 seconds. Tested on v12.1, Wolfram Cloud.
Remark
My solution is slower in v9.0.1. (72 seconds v.s. 39 seconds. ) Not sure about the reason.
Update
A solution with Compile
(fastest one so far):
help = Compile[{{mat, _Integer, 2}},
Table[If[4 > (lsti + 2 lstj // Union // Length), 1, 0], {lsti, mat}, {lstj, mat}](* ,
CompilationTarget -> C *)]
test = help@mt; // AbsoluteTiming
(* {9.29816, Null} *)
If you have a C compiler installed, add the CompilationTarget -> C
option and the code will be faster.
P.S.
I didn't expect ContainsAll
/SubsetQ
is so slow.