jQuery:循环元素以创建组合变体

jQuery: Cycle through elements to create combo 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,这是正确的。

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

我的母语不是英语

所以我解释不好

但我会尽力

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

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

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)

a single num would repeat combinations / previous array's length product times

and whole array values would repeat combinations / all previous array's length product(including self)

在情况 1 中组合为 4 时,最后一个字符重复 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>

据我了解,你要的是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 函数。