jQuery:遍历元素以创建组合变体

时间:2018-03-30 00:19:50

标签: javascript jquery for-loop foreach variations

前提:具有变体的电子商务系统。

用于此问题的HTML标记示例。

<div class = "variationType" data-variation-type = "size">
    <h3>Colour</h3>
    <div class = "variation" data-variation-type = "size"> small </div>
    <div class = "variation" data-variation-type = "size"> large </div>
</div>

<div class = "variationType" data-variation-type = "colour">
    <h3>Colour</h3>
    <div class = "variation" data-variation-type = "colour"> red </div>
    <div class = "variation" data-variation-type = "colour"> blue </div>
</div>

<div class = "variationType" data-variation-type = "material">
    <h3>Material</h3>
    <div class = "variation" data-variation-type = "material"> stone </div>
    <div class = "variation" data-variation-type = "material"> wood </div>
</div>

我需要做的是循环浏览上述每个变体类型和变体名称,以创建所有可能变体组合的列表(每种变体类型至少有一个变体)。如果只有两种变体类型,那么这很简单,但我也需要这样才能使用3+。

我的想法是,我需要以某种方式实现路径算法来遍历每种变体类型并创建唯一列表,但我不知道如何执行此操作。

为了获得可能的变化总量,我正在做以下事情。

// figure out how many variations there needs to be
var totalPathsToTake = 0;
var totalPathsTaken = 0;
jQuery('.variationType').each(function(i) {
    var variationType = jQuery(this).attr("data-variation-type");
    var totalVariationsInType = jQuery('.variation[data-variation-type="' + variationType + '"]').length;

    if(totalPathsToTake == 0){
        totalPathsToTake = totalPathsToTake + totalVariationsInType;
    } else {
        totalPathsToTake = totalPathsToTake * totalVariationsInType;
    }
});
console.log("total variations " + totalPathsToTake)

因此,上述代码将以8回复,这是正确的。

问题是,现在是什么?我将如何创建这些变体?任何帮助或建议都非常感激!

2 个答案:

答案 0 :(得分:1)

据我所知,你想要的是div.variations的所有排列。

实现这一目标的一种方法是认识到,当我们置换一种变体类型时,我们总是重复使用其后的变体类型的排列。这适用于这样的递归实现:

// make an array of variation types, and each entry is the list of possible values
const all = $('.variationType').map((i, el) => $('.variation', el)).toArray();

// recursive function, return all permutations of values for a array of variation types
function permute_variations(arr) {
  // base case of no variation types
  if (arr.length < 1)
    return [];
  // base case of a single variation type
  if (arr.length === 1)
    return arr[0].toArray();

  // recurse by getting the permutations of the following variation types
  const inner_arr = permute_variations(arr.slice(1));
  // now permute all values for this type with the permutations that we got
  return arr[0].map((i, v0) => inner_arr.map(e => [v0].concat(e))).toArray();
}

const result = permute_variations(all);
console.log(`Number of permutations: ${result.length}`);
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="variationType" data-variation-type="size">
  <h3>Colour</h3>
  <div class="variation" data-variation-type="size"> small </div>
  <div class="variation" data-variation-type="size"> large </div>
</div>

<div class="variationType" data-variation-type="colour">
  <h3>Colour</h3>
  <div class="variation" data-variation-type="colour"> red </div>
  <div class="variation" data-variation-type="colour"> blue </div>
</div>

<div class="variationType" data-variation-type="material">
  <h3>Material</h3>
  <div class="variation" data-variation-type="material"> stone </div>
  <div class="variation" data-variation-type="material"> wood </div>
</div>

结果是div.variation元素的三元组数组,您可以根据需要进行处理。

注意:请注意Array map()方法和jQuery map()方法之间的区别,因为您可以看到它们以相反的顺序调用带有索引和元素参数的lambda函数。

答案 1 :(得分:0)

我不是母语为英语的人

所以我无法解释清楚

但我会尽我所能

如果有任何建议,我们将不胜感激

首先,我简化了问题,找到两个数组的组合

var arr1 = ["0","1"]
var arr2 = ["0","1"]

我们都知道结果如下:
(第一个字符来自arr1) (最后一个字符来自arr2)

  • 00
  • 01
  • 10
  • 11

然后我将第二个数组的值更改为

var Second = ["0","1","2"]

结果是:

  • 00
  • 01
  • 02
  • 10
  • 11
  • 12

之后,我添加另一个数组

var Third = ["0","1"]

结果是:

  • 000
  • 001
  • 010
  • 011
  • 020
  • 021
  • 100
  • 101
  • 110
  • 111
  • 120
  • 121

我发现有一个逻辑可以确定单个num重复和整个数组值重复多少次

我们可以通过多个每个数组的长度来计算组合
(如果数组的长度大于0)

  

单个数字会重复combinations / previous array's length product

     

并且整个数组值将重复combinations / all previous array's length product(including self)

当组合在案例1中为4时,最后一个char重复1次,因为没有先前的数组

第一次重复4 / First.length = 2

当案例3中的组合为12时,结果的最后一个数组重复12/First.length = 6

第一个数组重复12/(First.length * Second.length * Third.length) = 1


所以在这里,希望这有帮助

var Result = []
var Final = []
var Combinations = 1

var First = ["0", "1", "2"]
var Empty = []
var Second = ["a", "b", "c", "d"]
var Third = ["+", "-"]

// assume there would be some empty array
var allList = [First, Second, Empty, Third].filter(n => n.length>0).reverse() // remove empty array and reverse

allList.forEach(arr => Combinations = arr.length > 0 ? Combinations * arr.length : Combinations) // calculate combinations
$("body").append("Combinations : " + Combinations + "<br>")

var Items = 1
var totalRepeatTimes = 1
var elementRepeatTimes = 1
allList.forEach((arr ,index) => {
    Items *= arr.length;
    // array repeat times
    totalRepeatTimes = Combinations/Items;

    // each char repeat times
    elementRepeatTimes = index > 0 ? elementRepeatTimes * allList[index - 1].length : elementRepeatTimes;
    
    // add result array to Final
    Final.push(RepeatArray(arr, elementRepeatTimes, totalRepeatTimes))
})

Result = Array(Combinations).fill("."); // prepare an array fill with empty string
Final.reverse().forEach(arr => { Result = Join(Result, arr) }) // Join all result array

Result.forEach((result, index)=> $("body").append((index+1) + " : " + result + "<br>") )

function RepeatArray(arr, elementRepeatTimes, totalRepeatTimes) {
    arr = RepeatElement(arr, elementRepeatTimes);
    arr = RepeatTotal(arr, totalRepeatTimes);
    return arr;
}

function RepeatElement(arr, elementRepeatTimes) {
    var newArr = [];
    arr.forEach(element => {
        for (var i = 0; i < elementRepeatTimes; i++) {
            newArr.push(element)
        }
    })
    return newArr;
}

function RepeatTotal(arr, totalRepeatTimes) {
    var newArr = [];
    for (var i = 0; i < totalRepeatTimes; i++) {
        newArr = newArr.concat(arr)
    }
    return newArr;
}

function Join(arr1, arr2) {
    var newArr = [];
    arr1.forEach((element, index) => {
        newArr.push(arr1[index].toString() + arr2[index].toString())
    })
    return newArr;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>