具有多字符替换的字符串组合(针对Java的收益率返回重写) [英] String combinations with multi-character replacement (yield return alternative re-write for Java)

查看:84
本文介绍了具有多字符替换的字符串组合(针对Java的收益率返回重写)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

还有另一个堆栈溢出帖子是针对与车辆登记号相关的算法创建的...


根据输入的车牌(例如ABC123)和
替换值列表(例如1替换为I)。我需要获取所有可能的
组合。


@ArturoMenchaca的答案非常适合C#,但我想它用Java编写,但是鉴于'yield'不可用,我真的无法为如何转换而费心。



您如何将此代码转换为Java?

 公共静态IEnumerable< string>组合(字符串s,字典< char,char>替换)
{
return组合(s,替换,0,string.Empty);
}

私有静态IEnumerable< string>组合(原始字符串,Dictionary< char,char>替换,int索引,字符串当前)
{
if(index == original.Length)产生返回电流;
else
{
foreach(组合中的变量项(原始,替换,索引+1,当前+原始[索引]))
收益返回项;

if(replacements.ContainsKey(original [index]))
foreach(组合中的变量项(原始,替换,索引+ 1,当前+替换[原始[index]]))
收益回报项目;
}
}

您应该先调用然后调用这样的方法。

  Dictionary< char,char> dict =新字典< char,char>(); 
dict [’1’] =‘I’;
dict [’3’] =‘B’;
dict [’A’] =‘H’;
dict ['O'] ='0';
dict ['0'] ='O';

var combs = Combinations( ABC123,dict);


解决方案

Java没有使用以下方法迭代值的功能像C# yield return 一样。



Java仅支持拉逻辑,使用< a href = https://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html rel = nofollow noreferrer> 枚举 迭代器 ,或 Spliterator (什么 Stream 使用)



如果有足够的内存,您当然可以将所有组合推到 ArrayList 中,然后从那里拉值。将 yield return 逻辑转换为 list.add()调用很容易,所以我假设您不会



IEnumerable 等效的Java是 Iterable ,因此您需要 Iterator 实现。



下面的代码可以做到这一点。它基于我对另一个问题的回答,因此请阅读该回答以获取对整体逻辑的解释,但基本上,您的示例就像在此锯齿状数组中生成字符组合:



{{'A','H'},{'B' },{'C'},{'1','I'},{'2'},{'3','B'}}



在下面的代码中,那个锯齿状的数组是 textChars 数组,但不是使用 char [] 使用 String ,因为 String 实际上只是一个只读的 char []

  public static Iterable< String>组合(字符串文本,字符串...替换项){
Map< Character,String> repl =新的HashMap<>();
用于(字符串r:替换项)
if(repl.putIfAbsent(r.charAt(0),r)!= null)
抛出new IllegalArgumentException(重复替换项:[ +替换项.get(r.charAt(0))+] vs [ + r +]));
String [] textChars = new String [text.length()];
长计数= 1;
for(int i = 0; i< textChars.length; i ++){
textChars [i] = repl.getOrDefault(text.charAt(i),text.substring(i,i + 1) ));
count = Math.multiplyExact(count,textChars [i] .length());
}
个长comboCount =计数;
return()-> new Iterator<>(){
private long combo = 0;
@Override
public boolean hasNext(){
return(this.combo< comboCount);
}
@Override
public String next(){
if(this.combo> = comboCount)
throw new NoSuchElementException();
long c = this.combo ++;
char [] buf = new char [textChars.length];
for(int i = buf.length-1; i> = 0; i--){
buf [i] = textChars [i] .charAt((int)(c%textChars [ i] .length()));
c / = textChars [i] .length();
}
返回新的String(buf);
}
};
}

Test

 组合( ABC123, 1I, 3B, AH, O0, 0O)。forEach(System.out :: println); 

输出



< ABC123
ABC12B
ABCI23
ABCI2B
HBC123
HBC12B
HBCI23
HBCI2B


There's another Stack Overflow post that was created for an algorithm related to vehicle registration numbers...

According to the entered license plate (eg. ABC123) and a list of replacement values (eg 1 replaced by I). I need to get all possibles combinations.

The answer by @ArturoMenchaca is perfect for C#, but I'd like it in Java, but given that 'yield' is not available I really can't wrap my head around how to convert it.

How would you translate this code to Java?

public static IEnumerable<string> Combinations(string s, Dictionary<char, char> replacements)
{
    return Combinations(s, replacements, 0, string.Empty);
}

private static IEnumerable<string> Combinations(string original, Dictionary<char, char> replacements, int index, string current)
{
    if (index == original.Length) yield return current;
    else
    {
        foreach (var item in Combinations(original, replacements, index + 1, current + original[index]))
            yield return item;

        if (replacements.ContainsKey(original[index]))
            foreach (var item in Combinations(original, replacements, index + 1, current + replacements[original[index]]))
                yield return item;
    }
}

You would call then call the method like this..

Dictionary<char, char> dict = new Dictionary<char,char>();
dict['1'] = 'I';
dict['3'] = 'B';
dict['A'] = 'H';
dict['O'] = '0';
dict['0'] = 'O';

var combs = Combinations("ABC123", dict);

解决方案

Java doesn't have a feature for iterating values using "push" logic, like the C# yield return does.

Java only supports "pull" logic, using Enumeration, Iterator, or Spliterator (what Stream uses).

If you have the memory for it, you could of course "push" all the combinations into an ArrayList, then "pull" values from there. Converting the yield return logic into list.add() calls is easy, so I'll assume you don't want that.

The Java equivalent of IEnumerable is Iterable, so you need an Iterator implementation.

The code below will do that. It is based on my answer to another question, so please read that answer for an explanation of the overall logic, but basically, your example would be like generating combinations of characters in this jagged array:

{{'A', 'H'}, {'B'}, {'C'}, {'1', 'I'}, {'2'}, {'3', 'B'}}

In the code below, that jagged array is the textChars array, but instead of using char[] it uses a String, because a String is really just a read-only char[].

public static Iterable<String> combinations(String text, String... replacements) {
    Map<Character, String> repl = new HashMap<>();
    for (String r : replacements)
        if (repl.putIfAbsent(r.charAt(0), r) != null)
            throw new IllegalArgumentException("Duplicate replacement: [" + repl.get(r.charAt(0)) + "] vs [" + r + "]");
    String[] textChars = new String[text.length()];
    long count = 1;
    for (int i = 0; i < textChars.length; i++) {
        textChars[i] = repl.getOrDefault(text.charAt(i), text.substring(i, i+1));
        count = Math.multiplyExact(count, textChars[i].length());
    }
    long comboCount = count;
    return () -> new Iterator<>() {
        private long combo = 0;
        @Override
        public boolean hasNext() {
            return (this.combo < comboCount);
        }
        @Override
        public String next() {
            if (this.combo >= comboCount)
                throw new NoSuchElementException();
            long c = this.combo++;
            char[] buf = new char[textChars.length];
            for (int i = buf.length - 1; i >= 0; i--) {
                buf[i] = textChars[i].charAt((int) (c % textChars[i].length()));
                c /= textChars[i].length();
            }
            return new String(buf);
        }
    };
}

Test

combinations("ABC123", "1I", "3B", "AH", "O0", "0O").forEach(System.out::println);

Output

ABC123
ABC12B
ABCI23
ABCI2B
HBC123
HBC12B
HBCI23
HBCI2B

这篇关于具有多字符替换的字符串组合(针对Java的收益率返回重写)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆